web-dev-qa-db-fra.com

Plusieurs jointures à gauche sur plusieurs tables dans une requête

J'ai une table master, qui contient des éléments stockés sur plusieurs niveaux, parents et enfants, et une deuxième table pouvant contenir ou non des données supplémentaires. J'ai besoin d'interroger deux niveaux de ma table principale et d'avoir une jointure à gauche sur ma deuxième table, mais en raison de l'ordre dans ma requête, cela ne fonctionnera pas.

SELECT something FROM master as parent, master as child
  LEFT JOIN second as parentdata ON parent.secondary_id = parentdata.id
  LEFT JOIN second as childdata ON child.secondary_id = childdata.id
WHERE parent.id = child.parent_id AND parent.parent_id = 'rootID'

La jointure gauche ne fonctionne qu'avec la dernière table de la clause from, je ne peux donc la faire fonctionner que pour l'une des jointures de gauche. Dans l'exemple ci-dessus, aucune des jointures de gauche ne fonctionnera car la première jointure de gauche pointe vers la première table de la clause from, la seconde ne fonctionnera jamais de la sorte.

Comment puis-je faire ce travail?

22
DeniseMeander

Ce type de requête devrait fonctionner - après la réécriture avec la syntaxe ANSI JOIN explicite:

SELECT something
FROM   master      parent
JOIN   master      child ON child.parent_id = parent.id
LEFT   JOIN second parentdata ON parentdata.id = parent.secondary_id
LEFT   JOIN second childdata ON childdata.id = child.secondary_id
WHERE  parent.parent_id = 'rootID'

Le déclencheur est qu'un JOIN explicite se lie avant "l'ancien style" CROSS JOIN avec virgule (,). je cite le manuel ici:

Dans tous les cas, JOIN se lie plus étroitement que les virgules séparant les éléments de la liste FROM-.

Après la réécriture de la première, toutes les jointures sont appliquées de gauche à droite (logiquement - sinon, Postgres est libre de réorganiser les tables dans le plan de requête) et cela fonctionne.

Juste pour me faire comprendre, cela fonctionnerait aussi:

SELECT something
FROM   master parent
LEFT   JOIN second parentdata ON parentdata.id = parent.secondary_id
,      master child
LEFT   JOIN second childdata ON childdata.id = child.secondary_id
WHERE  child.parent_id = parent.id
AND    parent.parent_id = 'rootID'

Mais la syntaxe explicite JOIN est généralement préférable, comme votre cas l'illustre encore une fois.

Et soyez conscient que plusieurs JOIN (LEFT) peuvent multiplier des lignes:

36
Erwin Brandstetter

Tu peux faire comme ça

SELECT something
FROM
    (a LEFT JOIN b ON a.a_id = b.b_id) LEFT JOIN c on a.a_aid = c.c_id
WHERE a.parent_id = 'rootID'
4
pradipgarala

Les instructions JOIN font également partie de la clause FROM. Plus formellement, un join_type est utilisé pour combiner deux from_item en un from_item , dont un multiple peut alors former une virgule -separated liste après le FROM. Voir http://www.postgresql.org/docs/9.1/static/sql-select.html .

La solution directe à votre problème est donc:

SELECT something
FROM
    master as parent LEFT JOIN second as parentdata
        ON parent.secondary_id = parentdata.id,
    master as child LEFT JOIN second as childdata
        ON child.secondary_id = childdata.id
WHERE parent.id = child.parent_id AND parent.parent_id = 'rootID'

Une meilleure option serait d’utiliser uniquement JOIN, comme cela a déjà été suggéré.

2
Daniel Sparing