Прежде всего, я думаю, что вы должны переименовать столбец subid
в superid
или parentid
или что-то в этом роде, потому что это B
, C
& D
, которые sub -пункты A
, а не наоборот.Возможно, непоследовательное именование является именно той причиной, по которой результаты вашего запроса кажутся вам непонятными, или вам трудно создать запрос, который возвращает правильные результаты.
Ваш запрос по существу возвращает элементы, которые являются некоторыми другимипредметы детей.Сами они могут иметь или не иметь своих детей.Например, если у B
, C
или D
есть дети, ваш запрос вернет этих детей в дополнение к B
, C
и D
.Это не совсем то, что вам нужно.
Здесь вам нужно не внутреннее соединение, а анти -соединение.Это когда результаты возвращаются на основании того факта, что что-то имеет не совпадение.Анти-объединения могут быть реализованы различными способами:
Используя LEFT JOIN
+ IS NULL
check:
SELECT A.*
FROM #acc A
LEFT JOIN #acc B ON A.mainid = B.subid
WHERE B.mainid IS NULL
Здесь мы соединяем таблицу с самим собой ивозвращение левой стороны объединения, в которой правая сторона не имеет совпадений (т.е. возвращение строк со значениями mainid
, которые никогда не встречаются в столбце subid
).
Использование NOT EXISTS
:
SELECT *
FROM #acc A
WHERE NOT EXISTS (
SELECT *
FROM #acc B
WHERE A.mainid = B.subid
)
Этот запрос можно интерпретировать следующим образом: возвращать каждую строку из #acc
, если не существует совпадения между mainid
этой строки и subid
любой другой строки.
Использование NOT IN
:
SELECT *
FROM #acc
WHERE mainid NOT IN (
SELECT subid
FROM #acc
)
Это кажется мне наиболее простым (хотя и не обязательно наиболее эффективным): возвращать строки, в которых mainid
отсутствует в спискевсе существующие subid
значения.Если вы использовали NULL
s вместо 0
в качестве значений subid
корневых элементов, вам также придется изменить последний запрос, добавив этот фильтр в подзапрос:
…
WHERE subid IS NOT NULL
В противном случаебудет работать неправильно.
Вы также можете прочитать эту тему: