Несколько левых объединений на нескольких таблицах в одном запросе
У меня есть одна таблица master
, в которой есть элементы, хранящиеся на нескольких уровнях, родители и дочерние элементы, и есть вторая таблица, которая может иметь или не иметь дополнительных данных. Мне нужно запросить два уровня из моей основной таблицы и иметь левое соединение на моей второй таблице, но из-за заказа в моем запросе это не сработает.
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'
Левое соединение работает только с последней таблицей в предложении from, поэтому я могу только заставить ее работать для одного из левых объединений. В приведенном выше примере ни одно из левых соединений не будет работать, потому что первые левые точки присоединения к первой таблице в предложении from, второй никогда не будет работать так.
Как я могу сделать эту работу?
Ответы
Ответ 1
Этот тип запроса должен работать - после переписывания с явным синтаксисом JOIN
:
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'
Срабатывание здесь заключается в том, что явный JOIN
связывает перед "старым стилем" CROSS JOIN
запятую (,
). Я цитирую руководство здесь:
В любом случае JOIN
связывается более плотно, чем запятые, разделяющие FROM
-list предметов.
После переписывания первого все объединения применяются слева направо (по логике - Postgres может свободно переставлять таблицы в плане запроса в противном случае), и это работает.
Просто чтобы выразить свою точку зрения, это тоже сработает:
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'
Но явный синтаксис JOIN
, как правило, предпочтительнее, как показывает ваш случай еще раз.
И помните, что несколько (LEFT
) JOIN
могут умножать строки:
Ответ 2
Вы можете сделать это следующим образом:
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'
Ответ 3
Операторы JOIN
также являются частью предложения FROM
, более формально join_type используется для объединения двух from_item в один from_item, несколько из которых затем могут формировать список, разделенный запятыми, после FROM
. См. http://www.postgresql.org/docs/9.1/static/sql-select.html.
Итак, прямое решение вашей проблемы:
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'
Лучшим вариантом было бы использовать только JOIN
, как уже было предложено.