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?
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 listeFROM
-.
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:
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'
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é.