[PG] Récupérer plusieurs fois plusieurs morceaux d'une table

Récupérer plusieurs fois plusieurs morceaux d'une table [PG] - SQL/NoSQL - Programmation

Marsh Posté le 06-11-2007 à 00:04:06    

Salut ! [:dawa]
 
j'ai eu quelques problèmes à résoudre le problème suivant, et j'aurais voulu savoir si vous aviez de meilleurs idées ... [:dawa]
 
 
Voilà le problème :

  • j'ai une table 'villes', avec dedans, un colonne 'nom' de type text, et une colonne 'code_postal', de type text aussi. La table contient donc une liste de ville et le code postal associée à cette ville
  • j'aurais voulu récupérer pour chaque département, les X (premières) villes (disons, par ordre de code postal, mais c'est pas vraiment important)


Donc imaginons que j'ai l'équivalent de 90 départements dans ma base, si je veux récupérer les 10 premières villes de chaque département, je dois récupérer 900 couples ville/code_postal.
 
 
Question : comment je fais ?
 
 
J'ai essayé plusieurs trucs :

  • récupérer le code postal, facile. Mais j'arrive pas à en faire grand chose
  • faire des tests en prenant que deux départements. Ça donnait quelque chose dans ce gout là (attention les yeux) :
Code :
  1. SELECT commune, code_postal
  2. FROM (
  3.     SELECT nom, code_postal
  4.     FROM villes
  5.     WHERE code_postal LIKE '01%'
  6.     LIMIT 5
  7. ) AS t
  8.  
  9. UNION
  10.  
  11. SELECT commune, code_postal
  12. FROM
  13. (
  14.     SELECT nom, code_postal
  15.     FROM villes
  16.     WHERE code_postal LIKE '02%'
  17.     LIMIT 5
  18. ) AS t
  19.  
  20. ORDER BY code_postal


... mais bon, à part coller 90 fois ce code, pas terrible non plus.
 
Là, j'ai réussi à me démerder avec une procédure stockée, qui fait ce copier/coller (en fait). Ça génère une grosse requête, que j'exécute dans un curseur, puis je retourne le curseur et je fais un FETCH ALL dessus [:klem3i1].
Ça me semble un peu gorret [:dawa]
 
 
Donc voilà, est-ce que vous auriez une meilleure solution ?

Reply

Marsh Posté le 06-11-2007 à 00:04:06   

Reply

Marsh Posté le 06-11-2007 à 21:00:57    

Ya pas de roxorz du SQL par là ? [:dawak]

Reply

Marsh Posté le 06-11-2007 à 22:40:48    

HFR c'est plus ce que c'était :o


---------------
"Hello IT ? Have you tried turning it off and on again ?"
Reply

Marsh Posté le 07-11-2007 à 15:48:06    

grmpf.
 
je pars fumer une clope, si je me souvient de ton problème à mon retour, je regarde [:magicbuzz]

Reply

Marsh Posté le 07-11-2007 à 16:19:50    

Voilà, inspire toi de ce petit test que je viens de faire :
 

Code :
  1. SELECT *
  2. FROM
  3. (
  4. SELECT tie.typtie, tie.sigtie,
  5. sum(1) over (partition BY tie.typtie ORDER BY tie.typtie, tie.sigtie rows unbounded preceding) AS incr
  6. FROM tie
  7. WHERE tie.codsoc = 2 -- c'est juste un filtre pour faire joli
  8. ORDER BY tie.typtie, tie.sigtie
  9. ) tmp
  10. WHERE tmp.incr <= 5 -- je veux les 5 premiers par groups de tie.typtie
  11. ORDER BY typtie, sigtie


 
Ici, c'est sous Oracle 10gR2.
Je ne garanti pas que ce soit transposable 100% de façon identique sous PostGreSQL.
 
Ceci dit, il s'agit uniquement de mots clés SQL-92, donc PostGreSQL respectant très bien cette norme, tu peux avoir bon espoir.

Reply

Marsh Posté le 07-11-2007 à 17:46:16    

tu peux aussi essayer de te démerder avec la doc de T-SQL, puisque la syntaxe est différente (et là j'ai pas le temps de regarder comment ça marche avec sql server)
http://msdn2.microsoft.com/fr-fr/library/ms189461.aspx

Reply

Marsh Posté le 07-11-2007 à 20:14:31    

Salut !
 
Merci d'avoir répondu :)
 
Bon, par contre, ça m'aide pas trop, puisque Postgres ne support pas les fonctions sur des fenêtres (le sum(1) OVER (...) ) :(
 
Ceci dit, je vois un peu comment tu faisais ça, je vais voir si je peux trouver un moyen de faire la même chose sans passer par ces fonctionnalités ...

Reply

Marsh Posté le 07-11-2007 à 20:22:43    

Ben sinon, tu fais une PS qui te retourne sous forme de table les 10 première villes d'un département. En faisant un inner join dessus à partir des départements, c'est gagné.

Reply

Marsh Posté le 07-11-2007 à 20:55:50    

Pas bête, c'était presque bon :(

 
Code :
  1. CREATE OR REPLACE FUNCTION city_by_dep(dep integer) RETURNS SETOF villes AS $$
  2. DECLARE
  3.     line RECORD;
  4. BEGIN
  5.     FOR line IN SELECT * FROM villes WHERE code_postal LIKE dep || '%' ORDER BY code_postal LIMIT 10 LOOP
  6.         RETURN next line;
  7.     END LOOP;
  8.     RETURN;
  9. END;
  10. $$ LANGUAGE plpgsql;
 

et :

Code :
  1. SELECT *
  2. FROM (
  3.     SELECT substring(code_postal FOR 2) AS dep FROM villes GROUP BY dep ORDER BY dep
  4. ) AS t
  5. JOIN city_by_dep(t.dep) ON true


mais bon, apparement, j'ai pas le droit d'utiliser "t.dep" dans l'appel à la procédure :/


Message édité par multani le 08-11-2007 à 00:19:22
Reply

Marsh Posté le 07-11-2007 à 20:56:36    

Bon, ceci dit, ça m'a permis du coup de comprendre comment on pouvait récupérer plusieurs lignes à partir d'un appel à une procédure [:dawa]

Reply

Marsh Posté le 07-11-2007 à 20:56:36   

Reply

Marsh Posté le 08-11-2007 à 00:10:08    

c'est exprès la faute de frappe dans la ligne 5 de ta fonction ?
 
parceque sinon, mise à part limitation praticulière de PG, et syntaxe mise à part (je maîtrise plutôt le T-SQL qui diffère énormément), le principe me semble tout à fait bon.
 
je vérifierai demain, mais il me semble que j'utilise justement ce système au boulot (pour une toute autre raison) et ça passe sans problème sous sql server. ce serait bien con que ça ne passe pas sous pg :/

Reply

Marsh Posté le 08-11-2007 à 00:22:15    

MagicBuzz a écrit :

c'est exprès la faute de frappe dans la ligne 5 de ta fonction ?


oups, en passant les mots clés en majuscule, j'ai oublié un E :p
 

MagicBuzz a écrit :

parceque sinon, mise à part limitation praticulière de PG, et syntaxe mise à part (je maîtrise plutôt le T-SQL qui diffère énormément), le principe me semble tout à fait bon.
 
je vérifierai demain, mais il me semble que j'utilise justement ce système au boulot (pour une toute autre raison) et ça passe sans problème sous sql server. ce serait bien con que ça ne passe pas sous pg :/


Bon, après, comme j'ai dis, j'ai découvert tout à l'heure comment utiliser une fonction pour récupérer plusieurs résultats, donc chuis ptêtre pas forcément super au point non plus.
 
Je poserais la question sur la ML postgresql-user pour voir si quelqu'un connaissant bien Postgres a une meilleure solution.
 
 
Merci :hello:

Reply

Marsh Posté le 08-11-2007 à 11:37:34    

Bon, j'ai fait mumuse tout à l'heure, et je me suis rendu compte que... sous SQL Server non plus on peut pas faire de jointure sur une fonction de ce genre... du moins les paramètres attendus ne peuvent pas provenir des autres tables.
 
Bref.
 
Voici un script complet qui marche chez moi :
 

Code :
  1. DROP FUNCTION Get10ComPerDep;
  2. DROP TABLE com;
  3. DROP TABLE dep;
  4.  
  5. CREATE TABLE dep
  6. (
  7.  nomdep char(23) NOT NULL PRIMARY KEY,
  8.  numdep char(2) NOT NULL
  9. );
  10. CREATE TABLE com
  11. (
  12.  insee char(5) NOT NULL PRIMARY KEY,
  13.  codpos char(5) NOT NULL,
  14.  nomcom char(26) NOT NULL,
  15.  nomdep char(23) NOT NULL REFERENCES dep(nomdep)
  16. );
  17.  
  18. CREATE INDEX ix_nomcom ON com (nomcom);
  19. CREATE INDEX ix_codpos ON com (codpos);
  20. go
  21.  
  22. CREATE FUNCTION Get10ComPerDep()
  23. returns @ret TABLE
  24. (
  25.  nomdep char(23),
  26.  codpos char(5),
  27.  nomcom char(26),
  28.  insee char(5) PRIMARY KEY
  29. )
  30. AS
  31. begin
  32.  declare @nomdep char(23);
  33.  
  34.  declare curdep cursor FOR
  35.  SELECT nomdep FROM dep;
  36.  
  37.  open curdep;
  38.  
  39.  fetch next FROM curdep INTO @nomdep;
  40.  
  41.  while @@fetch_status = 0
  42.  begin
  43.    INSERT INTO @ret (nomdep, codpos, nomcom, insee)
  44.    SELECT top 10 @nomdep, codpos, nomcom, insee FROM com WHERE nomdep = @nomdep ORDER BY codpos;
  45.  
  46.    fetch next FROM curdep INTO @nomdep;
  47.  end;
  48.  
  49.  close curdep;
  50.  deallocate curdep;
  51.  
  52.  RETURN;
  53. end;
  54. go
  55.  
  56. INSERT INTO dep (nomdep, numdep)
  57. SELECT DISTINCT departement, LEFT(codepos, 2)
  58. FROM insee
  59. ORDER BY 1;
  60.  
  61. INSERT INTO com (insee, codpos, nomcom, nomdep)
  62. SELECT insee, codepos, commune, departement
  63. FROM insee
  64. ORDER BY 1;
  65.  
  66. SELECT *
  67. FROM Get10ComPerDep()
  68. ORDER BY nomdep, nomcom;


 
(bon, au début je me prends la tête pour recopier "proprement" une table "INSEE" récupérée sur le net dans deux tables "com" et "dep", n'y prête pas attention ;))

Reply

Marsh Posté le 08-11-2007 à 11:50:54    

Ouais, j'avais pensé à faire un truc comme ça au début en fait ...
... sauf que je savais pas retourner plusieurs lignes d'un coup :D
 
D'où ma première "solution"  [:petrus75]
 
Donc là, ouais, en faisant une boucle sur les départements, puis une requête pour récupérer 10 villes et RETURN NEXT sur le résultat, c'est cool [:romf]

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed