Использование внутреннего соединения DISTINCT в SQL
У меня есть три таблицы: A, B, C, где A - много одного B, а B - несколько. Мне нужен список всех C в A.
Мои таблицы выглядят примерно так: A [id, valueA, lookupB], B [id, valueB, lookupC], C [id, valueC]. Я написал запрос с двумя вложенными SELECT, но мне интересно, возможно ли сделать INNER JOIN с DISTINCT каким-то образом.
SELECT valueC
FROM C
INNER JOIN
(
SELECT DISTINCT lookupC
FROM B INNER JOIN
(
SELECT DISTINCT lookupB
FROM A
)
A2 ON B.id = A2.lookupB
)
B2 ON C.id = B2.lookupC
EDIT:
Таблицы довольно большие, A - 500 тыс. Строк, B - 10 тыс. Строк, а C - 100 строк, поэтому есть много лишней информации, если я делаю базовое внутреннее соединение и использую DISTINCT в конце, например:
SELECT DISTINCT valueC
FROM
C INNER JOIN B on C.id = B.lookupB
INNER JOIN A on B.id = A.lookupB
Это очень, очень медленно (величины медленнее, чем вложенные SELECT, которые я делаю выше.
Ответы
Ответ 1
Я провел тест на MS SQL 2005, используя следующие таблицы: строки 400K, строки B 26K и строки C 450.
В оценочном плане запроса указано, что базовое внутреннее соединение будет в 3 раза медленнее, чем вложенные подзапросы, однако при фактическом запуске запроса базовое внутреннее соединение было в два раза быстрее, чем вложенные запросы. 297 мс на очень минимальном серверном оборудовании.
Какую базу данных вы используете, и в какие времена вы видите? Я думаю, если вы видите плохую производительность, то это, вероятно, проблема с индексами.
Ответ 2
Я считаю, что ваши отношения 1: m должны уже неявно создавать DISTINCT JOINs.
Но, если вы цель, это всего лишь C в каждом A, может быть проще просто использовать DISTINCT для внешнего запроса.
SELECT DISTINCT a.valueA, c.valueC
FROM C
INNER JOIN B ON B.lookupC = C.id
INNER JOIN A ON A.lookupB = B.id
ORDER BY a.valueA, c.valueC
Ответ 3
Это то, что вы имеете в виду?
SELECT DISTINCT C.valueC
FROM
C
INNER JOIN B ON C.id = B.lookupC
INNER JOIN A ON B.id = A.lookupB
Ответ 4
SELECT DISTINCT C.valueC
FROM C
LEFT JOIN B ON C.id = B.lookupC
LEFT JOIN A ON B.id = A.lookupB
WHERE C.id IS NOT NULL
Я не вижу веской причины, по которой вы хотите ограничить набор результатов A и B, потому что то, что вы хотите иметь, - это список всех C, на которые ссылается A. Я сделал отличный от C.valueC, потому что я догадался, что вам нужен уникальный список C.
EDIT. Я согласен с вашим аргументом. Даже если ваше решение выглядит немного вложенным, это, по-видимому, самый лучший и быстрый способ использовать ваши знания данных и уменьшить наборы результатов.
Нет никакой отдельной конструкции соединения, которую вы могли бы использовать, поэтому просто оставайтесь с тем, что у вас уже есть:)