#sql #oracle
Вопрос:
У меня есть две связанные таблицы Cars
AddItems
и соотношение 1 к 0 или много между ними, так что есть автомобили с дополнительными предметами или без них.
Мне нужен запрос, который всегда будет приводить к автомобилям в виде отдельных записей и дополнительных записей для дополнительных элементов автомобиля, таких как:
CarName | ItemName
======== =========
Car1 | <- car without additional items
Car2 | <- car with additional items but this solo record needed as well
Car2 | Item1
Car2 | Item2
Car3 |
Car3 | Item3
Если я использую простое ВНЕШНЕЕ СОЕДИНЕНИЕ СЛЕВА, я не смогу получить эту сольную запись автомобиля, когда автомобиль присоединился к дополнительным предметам.
Я мог бы получить что-то вроде:
SELECT carname,NULL AS itemname FROM cars
UNION
SELECT c.carname,ai.itemname
FROM cars c
LEFT JOIN additems ai ON ai.id_car=c.id
Есть ли какой-нибудь более простой/лучший (объединяющий) способ без ОБЪЕДИНЕНИЯ?
Комментарии:
1. Каков ваш конечный результат? Также, пожалуйста, опубликуйте примеры данных из таблицы дополнений?
2. Вы можете заменить на, если вы замените на a .
UNION
UNION ALL
LEFT JOIN
JOIN
3. СОЮЗ-это путь сюда. Вам нужна запись из автомобилей (без связи с элементом добавления) И запись для комбинации автомобилей/предметов (внутренняя связь соединения). Единственный способ объединить эти 2-это ОБЪЕДИНЕНИЕ.
Ответ №1:
UNION ALL
не выполняет дедупликацию (что необходимо, потому что запрос cars и то и LEFT JOIN
другое дают голые автомобили)
UNION
это дорого только потому, что удаляет дубликаты, часто вызывая сортировку. В первую очередь дешевле не создавать дубликаты.
-- all the casrs
SELECT carname,NULL AS itemname
FROM cars
UNION ALL
-- additional detail records, if any
SELECT c.carname,ai.itemname
FROM cars c
JOIN additems ai ON ai.id_car=c.id
ORDER BY 1,2 NULLS FIRST
;
Комментарии:
1. Хорошо, я согласен, хотя обе комбинации приведут к одному и тому же набору результатов, комбинация ОБЪЕДИНЕНИЯ ВСЕХ и ОБЪЕДИНЕНИЯ (вместо ОБЪЕДИНЕНИЯ и ОБЪЕДИНЕНИЯ СЛЕВА) является лучшим решением, поскольку идентификатор не включает процесс проверки и удаления повторяющихся записей.
Ответ №2:
Ваша версия в порядке. В качестве альтернативы вы можете использовать БОКОВЫЕ
SELECT t.*
FROM cars c
CROSS JOIN LATERAL (
SELECT c.carname, null FROM DUAL
UNION ALL
SELECT c.carname, i.itemname
FROM additems i
WHERE i.carname = c.carname
) t
ORDER BY 1, 2 NULLS FIRST;