[SQL] не работают два LEFT OUTER JOIN в одном запросе

ava3443

Есть две таблицы, tableA и tableB. tableA относится к tableB как один-ко-многим. Поле id есть в обеих таблицах, в tableA это primary key, в tableB это foreign key на tableA (не уверен, что я правильно выражаюсь )
Хочется сделать два отдельных LEFT OUTER JOIN, чтобы одним запросом получить запись из tableA вместе с двумя разными записями из tableB (если они есть).
Делаю такой запрос:
SELECT a.field1, a.field2, b1.data as field3, b2.data as field4
FROM tableA a
LEFT OUTER JOIN tableB b1 ON a.id = b1.id
LEFT OUTER JOIN tableB b2 ON a.id = b2.id
WHERE (b1.data = "data1" OR b1.data IS NULL) AND (b2.data = "data2" OR b2.data IS NULL)
Если в tableB есть 2 записи, в одной data="data1", в другой data="data2", то всё как надо: на выходе получаю поля из таблицы tableA + поле b1.data + поле b2.data (из двух разных строк таблицы tableB).
Если в tableB есть запись с data="data1", но нет записи с data="data2", то мне хочется получить поля из таблицы tableA + поле data из найденной записи (b1.data) + NULL вместо несуществующей записи. Однако, в этом случае запрос вообще ни одной строки не выдаёт.
P.S. База - Oracle 9.

gopnik1994

а для чего тебе outer? чем тебя простой left не устраивает?
 SELECT a.field1, a.field2, b1.data as field3, b2.data as field4
FROM tableA a
LEFT JOIN tableB b1 ON a.b1_id = b1.id
LEFT JOIN tableB b2 ON a.b2_id = b2.id

ava3443

а для чего тебе outer? чем тебя простой left не устраивает?
Записи в tableB, ссылающиеся на tableA, могут существовать, а могут и не существовать. Во втором случае я хочу увидеть NULL на месте полей из tableB. OUTER JOIN вроде именно для этого и сделан. А простой left мне вообще не выдаст ничего, если записей в tableB не найдёт.
SELECT a.field1, a.field2, b1.data as field3, b2.data as field4
FROM tableA a
LEFT JOIN tableB b1 ON a.b1_id = b1.id
LEFT JOIN tableB b2 ON a.b2_id = b2.id
Нет никаких b1_id и b2_id в таблице tableA. Есть поле id, являющееся primary key.

ava3443

Видимо, вместо LEFT OUTER JOIN-ов

SELECT a.field1, a.field2, b1.field as field3, b2.field as field4
FROM tableA a
LEFT OUTER JOIN tableB b1 ON a.id = b1.id
LEFT OUTER JOIN tableB b2 ON a.id = b2.id
WHERE (b1.data = "data1" OR b1.data IS NULL) AND (b2.data = "data2" OR b2.data IS NULL)
придётся использовать подзапросы:
SELECT a.field1, a.field2, 
(SELECT b1.field
FROM tableB b1
WHERE b1.id = a.id AND b1.data="data1") field3,
(SELECT b2.field
FROM tableB b2
WHERE b2.id = a.id AND b2.data="data2") field4
FROM tableA a

gopnik1994

маза нормализовать отношения...
у тебя какой-то кривой запрос...
то что ты написал с подзапросами - это обычный left join

ava3443

> то что ты написал с подзапросами - это обычный left join
нет. эти подзапросы могут и NULL вернуть, в отличие от LEFT JOIN.

gopnik1994

> эти подзапросы могут и NULL вернуть, в отличие от LEFT JOIN
почитай про LEFT JOIN и чем он отличается от обычного (inner) join'а

gopnik1994


SELECT a.field1, a.field2, b1.field, b2.field
FROM tableA a
LEFT JOIN tableB b1 ON b1.id = a.id AND b1.data="data1"
LEFT JOIN tableB b2 ON b2.id = a.id AND b2.data="data2"

yakoalek

Попробуй

tableB b1 right join a ON a.id = b1.id
LEFT OUTER JOIN tableB b2 ON a.id = b2.id

gopnik1994

хорош извращаться

kasatka

по-моему, вполне нормальный метод
Я в свое время писал селекты на полстраницы, так там и не такое было

daru

даже интересно, как бы ты подошел к вопросу, если бы там было 3 join'а...

ava3443

> почитай про LEFT JOIN и чем он отличается от обычного (inner) join'а
И чем отличается?

ava3443

> маза нормализовать отношения...
посмотрел сейчас, у меня 3 нормальная форма стопудово.

ava3443

Попробуй
tableB b1 right join a ON a.id = b1.id
LEFT OUTER JOIN tableB b2 ON a.id = b2.id
Супер, только мне вместо RIGHT JOIN нужен всё-таки RIGHT OUTER JOIN... Надо это попробовать, но вообще не вижу разницы с моим исходным запросом.

gopnik1994

а ты попробовал мой вариант?

gopnik1994

> И чем отличается?
именно тем, что, если запись не существует, проставит NULL...

ava3443

> а ты попробовал мой вариант?
Да, сейчас попробовал. Совсем не то, что нужно.
> именно тем, что, если запись не существует, проставит NULL...
Ты, видимо, путаешь LEFT JOIN с LEFT OUTER JOIN. В Оракле LEFT JOIN == LEFT INNER JOIN, насколько я понимаю, и NULL он никогда не проставит, потому как это самый обычный JOIN.
P.S. Всё равно, спасибо за помощь.

Lorin

начнём отсюда
Есть две таблицы, tableA и tableB.
таким образом твоё требование:
одним запросом получить запись из tableA вместе с двумя разными записями из tableB (если они есть).
по сути есть требование либо AND, либо OR = формулируй как хочешь, так как поле data у тебя одно и в одной таблице tableB, если это OR, что ты дико пытаешься реализовать двумя внешними джойнами, то это и всё лежит в трёх линейных запросах с одним джойном (обычным)

Lorin

есть ещё гениальные решения с селф-джойнами (странно, что ты их не написал )

ava3443

Да, я пытался это одним запросом сделать: нужно, чтобы такой запрос мог выполниться несколько десятков тысяч раз за несколько секунд. Ну и я думал, что если загнать это всё в один запрос, то оно быстрее будет
Сейчас сделал тремя SELECTами - вроде скорость приемлима...

ava3443

> есть ещё гениальные решения с селф-джойнами (странно, что ты их не написал )
Я в них не рюхаю пока

gopnik1994

ты меня прям заставил засомневаться в своих познаниях оракла
я даже доку открыт и вот что нашел:

join_type The join_type indicates the kind of join being performed:
(.) Specify INNER to indicate explicitly that an inner join is being performed. This
is the default.
(.) Specify RIGHT to indicate a right outer join.
(.) Specify LEFT to indicate a left outer join.
(.) Specify FULL to indicate a full or two-sided outer join. In addition to the inner
join, rows from both tables that have not been returned in the result of the inner
join will be preserved and extended with nulls.
(.) You can specify the optional OUTER keyword following RIGHT, LEFT, or FULL
to explicitly clarify that an outer join is being performed
.
читать до просветления

ava3443

да, слажал я
Оставить комментарий
Имя или ник:
Комментарий: