Forum Programmation.SQL Problème de jointure multiple

Posté par  (site web personnel) .
Étiquettes : aucune
0
26
avr.
2006
Bonjour, j'essaye toujours de migrer ma base oracle vers Postgre et je tombe sur un épineux problème de jointures multiples :

J'ai pris le parti de recommencer à transformer le code

je part donc de (format oracle) :
select a.*,
b.met_id,b.met_lib,
h.fct_id,
c.fct_lib,
d.ct_id,d.ct_lib,j.ct_valide,
e.typ_id,e.typ_lib,
f.notfct_val,
i.ser_lib
from
collaborateurs a,
metiers b,
fonction c,
competences_tech d,
type_ct e,
li_col_ct_fct f,
li_col_met g,
li_col_fct h,
service i,
LI_MET_TYP_CT j
where
(a.col_id=g.col_id(+)
and g.met_id=b.met_id(+))
and (a.col_id=h.col_id(+)
and h.fct_id=c.fct_id(+))
and (f.col_id=a.col_id and f.met_id=b.met_id and d.ct_id=f.ct_id)
and (j.typ_id=e.typ_id)
and (a.ser_id = i.ser_id(+))
and (j.ct_id = d.ct_id)
and (j.met_id = g.met_id)
order by a.col_nom asc , c.fct_lib asc , e.typ_lib asc , j.ct_valide desc, d.ct_lib asc;


à
select collaborateurs.*,
metiers.met_id,metiers.met_lib,
li_col_fc.fct_id,
fonction.fct_lib,
competences_tech.ct_id,competences_tech.ct_lib,
LI_MET_TYP_CT.ct_valide,
type_ct.typ_id,type_ct.typ_lib,
li_col_ct_fct.notfct_val,
service.ser_lib
from
-- collaborateurs,
-- metiers ,
-- fonction ,
competences_tech ,
type_ct ,
li_col_ct_fct ,
-- li_col_met ,
-- li_col_fct ,

LI_MET_TYP_CT,

collaborateurs left outer join li_col_met on (collaborateurs.col_id=li_col_met.col_id)
left outer join li_col_fct on (collaborateurs.col_id=li_col_fct.col_id)
left outer join service on (collaborateurs.ser_id = service.ser_id),
li_col_fct left outer join fonction on (li_col_fct.fct_id=fonction.fct_id),
li_col_met left outer join metiers on (li_col_met.met_id=metiers.met_id)
where
-- li_col_met.met_id=metiers.met_id(+))
LI_MET_TYP_CT.typ_id=type_ct.typ_id
-- and (collaborateurs.col_id=li_col_fc.col_id(+)
-- and li_col_fc.fct_id=fonction.fct_id(+))
and (li_col_ct_fct.col_id=collaborateurs.col_id and li_col_ct_fct.met_id=metiers.met_id and competences_tech.ct_id=li_col_ct_fct.ct_id) and
(LI_MET_TYP_CT.typ_id=type_ct.typ_id)
-- and (collaborateurs.ser_id = service.ser_id(+))
and (LI_MET_TYP_CT.ct_id = competences_tech.ct_id)
and (LI_MET_TYP_CT.met_id = li_col_met.met_id)
order by collaborateurs.col_nom asc , fonction.fct_lib asc , type_ct.typ_lib asc , LI_MET_TYP_CT.ct_valide desc, competences_tech.ct_lib asc;


J'ai volontairement laissé en commentaires certaines lignes pour la clarté (il s'agit des lignes ayant été réécrites).

Le problème c'est que Pgsql (et tout autre SGBD sql92 et +) me crache :
"ERROR: table name "li_col_fct" specified more than once"

Ce qui est effectivement vrai car j'utilise la table li_col_fct comme table droite d'une première jointure, puis comme table gauche d'une autre jointure :

[collaborateurs] left outer join li_col_fct on (collaborateurs.col_id=li_col_fct.col_id)
et
li_col_fct left outer join fonction on (li_col_fct.fct_id=fonction.fct_id)

Comment puis je me sortir de ce mauvais pas ?

Merci d'avance !
  • # anchaîner les left outer join

    Posté par  . Évalué à 4.

    ...
    collaborateurs left outer join li_col_met on (collaborateurs.col_id=li_col_met.col_id)
    left outer join li_col_fct on (collaborateurs.col_id=li_col_fct.col_id)
    left outer join fonction on (li_col_fct.fct_id=fonction.fct_id),
    ...

    Dam
    • [^] # Re: enchaîner les left outer join

      Posté par  (site web personnel) . Évalué à 2.

      Ca me fait me poser une bonne question

      Est-ce que

      t1 left outer join t2 on (...)
      left outer join t3 on (...)

      est équivalent à

      t1 left outer join t2 on (...),
      t1 left outer join t3 on (...)

      Ou alors équivalent à

      t1 left outer join t2 on (...),
      t2 left outer join t3 on (...)

      ?

      « Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker

      • [^] # Re: enchaîner les left outer join

        Posté par  . Évalué à 2.

        Ben... je ne suis pas expert SQL mais j'ai l'impression que seule la première expression est valide alors que les deux autres provoquent le même style de message d'erreur que ce que tu as posté.
        • [^] # Re: enchaîner les left outer join

          Posté par  (site web personnel) . Évalué à 2.

          Oui car il ya redondances.

          MAis je fais comment, quand mes jointures sont redondantes, je suis obligé de faire deux tables ?

          « Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker

          • [^] # Re: enchaîner les left outer join

            Posté par  . Évalué à 1.

            Ben... où est le problème avec la première syntaxe? Ca ne passe pas sous PostgreSQL?
          • [^] # Re: enchaîner les left outer join

            Posté par  . Évalué à 2.

            J'ai repensé à cette histoire hier soir, et je vois où est ton problème. A mon avis tu es obligé d'imbriquer des select :

            Un truc du genre :

            select ... from t4 left outer join (select ... from t1 left outer join t2 on (...) left outer join t3 on (...)) on (...))
  • # Un essai en sql propre...

    Posté par  . Évalué à 3.

    SELECT A.*, B.MET_ID,B.MET_LIB, H.FCT_ID, C.FCT_LIB
         , D.CT_ID,D.CT_LIB,J.CT_VALIDE
         , E.TYP_ID,E.TYP_LIB, F.NOTFCT_VAL, I.SER_LIB
    FROM   COLLABORATEURS A 
           LEFT OUTER JOIN LI_COL_MET G
              ON A.COL_ID=G.COL_ID
           LEFT OUTER JOIN METIERS B
              ON G.MET_ID=B.MET_ID
           LEFT OUTER JOIN LI_COL_FCT H
              ON A.COL_ID=H.COL_ID
           LEFT OUTER JOIN FONCTION C
              ON H.FCT_ID=C.FCT_ID
           LEFT OUTER JOIN SERVICE I
              ON A.SER_ID = I.SER_ID
           INNER JOIN LI_COL_CT_FCT F
              ON (A.COL_ID = F.COL_ID AND F.MET_ID = B.MET_ID)
           INNER JOIN COMPETENCES_TECH D
              ON F.CT_ID  = D.CT_ID
           INNER JOIN LI_MET_TYP_CT J
              ON (J.CT_ID  = D.CT_ID AND J.MET_ID = G.MET_ID)
           INNER JOIN TYPE_CT E
              ON J.TYP_ID = E.TYP_ID
    ORDER BY A.COL_NOM ASC 
           , C.FCT_LIB ASC
           , E.TYP_LIB ASC
           , J.CT_VALIDE DESC
           , D.CT_LIB ASC;
    
    Note que les conditions de jointure dans ta requête de départ
    (a.col_id=g.col_id(+) and g.met_id=b.met_id(+))
    et
    f.col_id=a.col_id and f.met_id=b.met_id
    se contredisent : la première fait qu'on peut garder, pour la table B, des lignes "vides" (jointures externes), alors que la deuxième impose que b.met_id soit non nul... Tu peux imposer directement une jointure interne entre B et G, au lieu d'une jointure externe, tu pourrais gagner un peu en perf, et surtout en cohérence... et, du coup, aussi une jointure interne entre A et G. Par ailleurs, les "SELECT table.*" sont à proscrire en règle générale (à l'exception, peut-être, d'applications du genre phpPgAdmin):
    1. quelqu'un qui arrive après devra regarder le schéma complet de la table pour connaître toutes les colonnes que tu appelles ainsi
    2. Oracle te renvoie toutes les colonnes, alors que tu n'en as peut-être pas besoin -> perte de perf
    3. si tu changes le schéma de la table (ajout de colonnes), alors la requête les enverra aussi (cf. 2)
    4. Oracle doit déterminer lui-même la liste des colonnes -> perte de perf par rapport à une requête où tu listes explicitement les colonnes.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.