Problème de requete sql..nécessité d'une requete récursive??

Problème de requete sql..nécessité d'une requete récursive?? - SQL/NoSQL - Programmation

Marsh Posté le 24-07-2005 à 23:52:15    

Bonjour,  
je suis sous SQL ORACLE
voilà dans ma table T_HISTORIQUE j'ai l'historique des numéros qu'a pris un élément:  
table T_HISTORIQUE dont les colonnes sont:
numéro initial "numInit"
numéro final   "numFin"
date de changement de numéro "dateChang"
 
A la création de mon élément, j'insère 0 dans "numéro initial" puis le numéro de mon élément dans "numéro final". Ensuite à chaque modification de numéro j'insère le numéro initial et final dans la table.
Un numéro ne peut etre utilisé qu'une seule fois meme si les éléments sont différents.
 
Je souhaite écrire une requete qui me ramène pour un dernier numéro final d'un élément donné,  
l'ensemble des numéros qu'il a pris, ainsi que les dates de changements!
(il n'y a pas de clé primaire unique qui me permette de tout ramener d'un coup)
Je n'arrive pas à écrire une telle requete!!
 
j'ai tenté  
 
SELECT T1.numInit, T1.numFin
FROM T_HISTORIQUE T1, T_HISTORIQUE T2
WHERE  
T1.numFin = T2.numInit
 
mais je voudrais aussi mettre la condition que le dernier numéro pris par mon élément soit un paramètre!
 
Si je peux faire cela en une requete ce serait bien   :)

Reply

Marsh Posté le 24-07-2005 à 23:52:15   

Reply

Marsh Posté le 25-07-2005 à 09:30:55    

Je ne l'ai pas lue en entier mais j'ai trouve sur
http://sqlpro.developpez.com/SQL_AZ_991.html
un truc tres ressemblant

Citation :


5.1.2 Récursion
 
 
Nous allons maintenant voir comment fonctionne la récursivité au sein de SQL...
Pour cela construisons notre jeu d'essais :
 
 
CREATE TABLE T_VOLS_VLS
(VLS_ID       INTEGER NOT NULL PRIMARY KEY,
 VLS_REF      CHAR(6) NOT NULL,
 VLS_DEPART   VARCHAR(16),
 VLS_ARRIVEE  VARCHAR(16)) INSERT INTO T_VOLS_VLS VALUES (1, 'AF714', 'PARIS', 'MARSEILLE')
INSERT INTO T_VOLS_VLS VALUES (2, 'AL908', 'PARIS', 'LYON')
INSERT INTO T_VOLS_VLS VALUES (3, 'AF321', 'PARIS', 'BORDEAUX')
INSERT INTO T_VOLS_VLS VALUES (4, 'AF978', 'BORDEAUX', 'MARSEILLE')
INSERT INTO T_VOLS_VLS VALUES (5, 'AL478', 'BORDEAUX', 'NICE')
INSERT INTO T_VOLS_VLS VALUES (6, 'AL974', 'NICE', 'LYON')
INSERT INTO T_VOLS_VLS VALUES (7, 'AL451', 'BORDEAUX', 'LILLE')
INSERT INTO T_VOLS_VLS VALUES (8, 'AF158', 'MARSEILLE', 'LYON')
INSERT INTO T_VOLS_VLS VALUES (9, 'AF159', 'MARSEILLE', 'BORDEAUX')
INSERT INTO T_VOLS_VLS VALUES (10, 'AF189', 'LYON', 'NICE')
INSERT INTO T_VOLS_VLS VALUES (11, 'AL458', 'NICE', 'PARIS')
INSERT INTO T_VOLS_VLS VALUES (12, 'AL117', 'MARSEILLE', 'PARIS')
INSERT INTO T_VOLS_VLS VALUES (13, 'AL444', 'BORDEAUX', 'LYON')
INSERT INTO T_VOLS_VLS VALUES (14, 'AL400',  'BORDEAUX', 'NANTES')
INSERT INTO T_VOLS_VLS VALUES (15, 'AF601',  'LYON', 'NANTES')
 
 
Le but est de trouver s'il est possible det se rendre, par exemple de PARIS à NANTES ou bien de NICE à BORDEAUX...
 
 
WITH RECURSIVE trajet (depart, arrivee)
AS (SELECT VLS_DEPART, VLS_ARRIVEE
    FROM   T_VOLS_VLS
    UNION  ALL
    SELECT debut.depart, suite.VLS_ARRIVEE
    FROM   trajet debut
           INNER JOIN T_VOLS_VLS suite
                 ON debut.arrive = suite.VLS_DEPART)
SELECT *
FROM   trajet
WHERE  depart = 'NICE'
   AND arrivee = 'BORDEAUX'
 
 
 
En fait le travail de circulation dans l'arbre se fait dans la clause WITH RECURSIVE. L'expression principale de requête n'est là que pour filtrer les résultats.
Lors du premier cycle, les données sont les suivantes :
 
 
depart           arrivee          
---------------- ----------------  
BORDEAUX         BORDEAUX
BORDEAUX         LILLE
BORDEAUX         LYON
BORDEAUX         LYON
BORDEAUX         LYON
BORDEAUX         MARSEILLE
BORDEAUX         NANTES
BORDEAUX         NANTES
BORDEAUX         NICE
BORDEAUX         NICE
BORDEAUX         PARIS
BORDEAUX         PARIS
LYON             LYON
LYON             NANTES
LYON             NICE
LYON             PARIS
MARSEILLE        BORDEAUX
MARSEILLE        BORDEAUX
MARSEILLE        LILLE
MARSEILLE        LYON
MARSEILLE        LYON
MARSEILLE        LYON
MARSEILLE        MARSEILLE
MARSEILLE        MARSEILLE
MARSEILLE        NANTES
MARSEILLE        NANTES
MARSEILLE        NICE
MARSEILLE        NICE
MARSEILLE        PARIS
NICE             BORDEAUX
NICE             LYON
NICE             LYON
NICE             MARSEILLE
NICE             NANTES
NICE             NICE
NICE             PARIS
PARIS            BORDEAUX
PARIS            BORDEAUX
PARIS            LILLE
PARIS            LYON
PARIS            LYON
PARIS            LYON
PARIS            MARSEILLE
PARIS            MARSEILLE
PARIS            NANTES
PARIS            NANTES
PARIS            NICE
PARIS            NICE
PARIS            PARIS
 
 
Nous avons en fait tous les trajets possibles directs ou avec une escale. A notez que si nous avions utilisé UNION au lieu de UNION ALL nous aurions eût moins de résultats, en fait 31 au lieu de 49, cela aurait signifié que nous nous fichons de savoir quelle est la ville étpae de l'escale !
Lors du second cycle les données sont :
 
 
depart           arrivee          
---------------- ----------------  
BORDEAUX         BORDEAUX
BORDEAUX         BORDEAUX
BORDEAUX         BORDEAUX
BORDEAUX         LILLE
BORDEAUX         LILLE
BORDEAUX         LYON
BORDEAUX         LYON
BORDEAUX         LYON
BORDEAUX         LYON
BORDEAUX         LYON
BORDEAUX         LYON
BORDEAUX         LYON
BORDEAUX         MARSEILLE
BORDEAUX         MARSEILLE
BORDEAUX         MARSEILLE
BORDEAUX         MARSEILLE
BORDEAUX         NANTES
BORDEAUX         NANTES
BORDEAUX         NANTES
BORDEAUX         NANTES
BORDEAUX         NANTES
BORDEAUX         NICE
BORDEAUX         NICE
BORDEAUX         NICE
BORDEAUX         NICE
BORDEAUX         NICE
BORDEAUX         PARIS
BORDEAUX         PARIS
BORDEAUX         PARIS
LYON             BORDEAUX
LYON             LYON
LYON             LYON
LYON             MARSEILLE
LYON             NANTES
LYON             NANTES
LYON             NICE
LYON             NICE
LYON             PARIS
MARSEILLE        BORDEAUX
MARSEILLE        BORDEAUX
MARSEILLE        BORDEAUX
MARSEILLE        BORDEAUX
MARSEILLE        LILLE
MARSEILLE        LILLE
MARSEILLE        LYON
MARSEILLE        LYON
MARSEILLE        LYON
MARSEILLE        LYON
MARSEILLE        LYON
MARSEILLE        LYON
MARSEILLE        LYON
MARSEILLE        LYON
MARSEILLE        MARSEILLE
MARSEILLE        MARSEILLE
MARSEILLE        MARSEILLE
MARSEILLE        NANTES
MARSEILLE        NANTES
MARSEILLE        NANTES
MARSEILLE        NANTES
MARSEILLE        NANTES
MARSEILLE        NICE
MARSEILLE        NICE
MARSEILLE        NICE
MARSEILLE        NICE
MARSEILLE        NICE
MARSEILLE        PARIS
MARSEILLE        PARIS
MARSEILLE        PARIS
MARSEILLE        PARIS
MARSEILLE        PARIS
NICE             BORDEAUX
NICE             BORDEAUX
NICE             LILLE
NICE             LYON
NICE             LYON
NICE             LYON
NICE             LYON
NICE             LYON
NICE             MARSEILLE
NICE             MARSEILLE
NICE             NANTES
NICE             NANTES
NICE             NANTES
NICE             NICE
NICE             NICE
NICE             NICE
NICE             PARIS
NICE             PARIS
NICE             PARIS
PARIS            BORDEAUX
PARIS            BORDEAUX
PARIS            BORDEAUX
PARIS            BORDEAUX
PARIS            LILLE
PARIS            LILLE
PARIS            LYON
PARIS            LYON
PARIS            LYON
PARIS            LYON
PARIS            LYON
PARIS            LYON
PARIS            LYON
PARIS            LYON
PARIS            MARSEILLE
PARIS            MARSEILLE
PARIS            MARSEILLE
PARIS            MARSEILLE
PARIS            NANTES
PARIS            NANTES
PARIS            NANTES
PARIS            NANTES
PARIS            NANTES
PARIS            NICE
PARIS            NICE
PARIS            NICE
PARIS            NICE
PARIS            NICE
PARIS            PARIS
PARIS            PARIS
PARIS            PARIS
PARIS            PARIS
 
 

Reply

Marsh Posté le 25-07-2005 à 09:37:36    

Sous Oracle c'est l'opérateur CONNECT BY PRIOR qu'il faut utiliser ;)
 

Code :
  1. SELECT numInit, numFin
  2. FROM T_HISTORIQUE
  3. STAR WITH numInit = 0
  4. CONNECT BY PRIOR numFin = numInit


 
START WITH ne doit pas être obligatoire, ça te permet de commencer la hiérarchie où tu veux.
 
Un exemple bien connu de cette fonction est la requête de restitution du plan d'exécution qui permet de mettre en page :
 

Code :
  1. select LPAD(' ',2*(LEVEL-1))||operation  "OPERATION",
  2. options     "TYPE_ACCES",
  3. DECODE(TO_CHAR(id),'0','COST= '|| NVL(TO_CHAR(position),'Indefini'), object_name) "NOM_OBJET",
  4. id || '-' || NVL(parent_id,0) || '-' || NVL(position,0) "ORDRE",
  5. ' COUT=' || COST ||','||'Card=' || CARDINALITY "Cout Op"
  6. From plan_table
  7. start with id = 0
  8. and statement_id = 'X'
  9. connect by prior id = parent_id
  10. and statement_id = 'X';


Reply

Marsh Posté le 25-07-2005 à 10:08:14    

j'en profite;
existe t'il un equivalent de ces fonctions sous MYSQL (au vu de la doc je crois pas mais bon...)

Reply

Marsh Posté le 25-07-2005 à 10:08:55    

ça ne me surprendrait que moyennement :D
 
Mais je dois admettre que je ne sais pas :/

Reply

Marsh Posté le 25-07-2005 à 14:43:36    

Nope, pas plus que sous SQL Server (grosse lacune d'ailleurs).
 
Sous SQL Server, on peut s'en tirer avec une PS, pour MySQL, à moins d'avoir la toute dernière version qui supporte aussi les PS, je pense que t'es obligé de passer par du code PHP ou autre.

Reply

Marsh Posté le 28-07-2005 à 00:08:41    

En fait il doit y avoir 2 écoles :
- ceux qui veulent tout faire en SQL car ils préfèrent
- ceux qui, comme moi, trouvent que ces problèmes sont parfaits à résoudre avec un langage de programation fait pour, sans faire faire tout le travail au SGBD.
 
A mon avis les 2 avis sont bons, mais à voir niveau rapidité (ce qui doit dépendre de bcp de facteurs).

Reply

Marsh Posté le 26-08-2007 à 12:35:38    

La création de requêtes récursive à la norme SQL:1999 (WITH RECURSIVE / UNION ALL) existe dans les SGBDR suivants :
IBM DB2 v8 et suivants
SQL Server 2005 (et 2008)
Elle n'existe pas dans les autres SGBDR comme MySQL, Oracle, PostGreSQL, Interbase, FireBird....
 
Oracle propose CONNECT BY / PRIOR, mais ne peut traiter que le parcours d'arbres par le parcours de graphes. C'est une lacule du moteur Oracle et c'est pourquoi le commité de normalisation de SQL n'a pas retenue la solution de Oracle.
 
Pour des détails sur les requêtes récursives, vous trouverez bientôt un article complet sur mon site : http://sqlpro.developpez.com (ou http://sql.developpez.com)
 
Quand à faire cela sur le client, c'est une simple problématique de perf. Sivous avez peu de données et une profondeur de scrutation récursive très faible, c'est faisable. Mais au volume de données ce sera toujours le SGBDR qui gagnera car il optimise et évite les aller et retour entre le serveur et le client.
 
A +
 

Reply

Marsh Posté le 27-08-2007 à 14:20:39    

betsamee a écrit :

Je ne l'ai pas lue en entier mais j'ai trouve sur
http://sqlpro.developpez.com/SQL_AZ_991.html
un truc tres ressemblant


Ton site avait déjà été indiqué dès le départ ;)
 
Très bon article en tout cas :jap:
 
Vu que t'as l'air de t'y connaître bien plus que moi, je te propose de regarder ça :
http://forum.hardware.fr/hfr/Progr [...] 6416_1.htm
 
Et me dire ce que tu en penses, les erreurs, les trucs à ajouter, etc. ;)


Message édité par MagicBuzz le 27-08-2007 à 14:21:58
Reply

Sujets relatifs:

Leave a Replay

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