SQL - Как вернуть строки из левой таблицы, не найденные в правой таблице?
У меня есть две таблицы с похожими именами столбцов, и мне нужно вернуть записи из левой таблицы, которые не найдены в правой таблице? У меня есть первичный ключ (столбец), который поможет мне сравнить обе таблицы. Какое соединение предпочтительнее?
Ответы
Ответ 1
Если вы просите T-SQL, то сначала рассмотрите основы. Существует три типа объединений, каждый из которых имеет собственный набор фаз логической обработки, как:
- A
cross join
является самым простым. Он реализует только одну фазу обработки логических запросов - a Cartesian Product
. Эта фаза работает на двух таблицах, предоставляемых в качестве входных данных для соединения, и производит декартово произведение этих двух. То есть каждая строка с одного входа сопоставляется со всеми строками от другого. Итак, если у вас есть m строк в одной таблице и n строк в другой, вы получите m × n строк в результате.
- Затем
Inner joins
: они применяют две фазы обработки логических запросов: A Cartesian product
между двумя входными таблицами как в перекрестном соединении, а затем filters
строки на основе предиката, указанного в пункте ON
(также известный как Join condition
).
- Далее идет третий тип объединений
Outer Joins
:
В outer join
вы помечаете таблицу как таблицу preserved
, используя ключевые слова LEFT OUTER JOIN
, RIGHT OUTER JOIN
или FULL OUTER JOIN
между именами таблиц. Ключевое слово OUTER
optional
. Ключевое слово LEFT
означает, что строки left table
сохраняются; ключевое слово RIGHT
означает, что строки в right table
сохраняются; и ключевое слово FULL
означает, что строки в таблицах both
LEFT
и RIGHT
сохраняются. Третья фаза обработки логических запросов outer join
идентифицирует строки из сохраненной таблицы, которые не нашли совпадений в другая таблица основана на предикате ON
. Эта фаза добавляет эти строки в таблицу результатов, создаваемую первыми двумя этапами объединения, и использует NULL
метки в качестве заполнителей для атрибутов с неподдерживаемой стороны соединения в этих внешних строках.
Теперь, если мы посмотрим на вопрос:
Чтобы вернуть записи из левой таблицы, которые не найдены в правой таблице, используйте LEFT OUTER JOIN
и отфильтруйте строки с NULL
значениями атрибутов с правой стороны соединения.
Ответ 2
Попробуйте это
SELECT f.*
FROM first_table f LEFT JOIN second_table s ON f.key=s.key
WHERE s.key is NULL
Подробнее читайте в этой статье: Соединения на сервере Sql
![enter image description here]()
Ответ 3
Я не могу добавить ничего, кроме примера кода, к двум другим ответам: однако, я считаю, что это может быть полезно увидеть в действии (другие ответы, на мой взгляд, лучше, потому что они объясняют это).
DECLARE @testLeft TABLE (ID INT, SomeValue VARCHAR(1))
DECLARE @testRight TABLE (ID INT, SomeOtherValue VARCHAR(1))
INSERT INTO @testLeft (ID, SomeValue) VALUES (1, 'A')
INSERT INTO @testLeft (ID, SomeValue) VALUES (2, 'B')
INSERT INTO @testLeft (ID, SomeValue) VALUES (3, 'C')
INSERT INTO @testRight (ID, SomeOtherValue) VALUES (1, 'X')
INSERT INTO @testRight (ID, SomeOtherValue) VALUES (3, 'Z')
SELECT l.*
FROM
@testLeft l
LEFT JOIN
@testRight r ON
l.ID = r.ID
WHERE r.ID IS NULL
Ответ 4
Эта страница дает приличную разбивку различных типов соединений, а также визуализации диаграмм venn, чтобы помочь... ну... визуализировать разницу в соединениях.
Как говорится в комментариях, это довольно простой запрос из звуков, поэтому вы должны попытаться понять различия между соединениями и тем, что они на самом деле означают.
Отъезд http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
Вы ищете запрос, например:
DECLARE @table1 TABLE (test int)
DECLARE @table2 TABLE (test int)
INSERT INTO @table1
(
test
)
SELECT 1
UNION ALL SELECT 2
INSERT INTO @table2
(
test
)
SELECT 1
UNION ALL SELECT 3
-- Here the important part
SELECT a.*
FROM @table1 a
LEFT join @table2 b on a.test = b.test -- this will return all rows from a
WHERE b.test IS null -- this then excludes that which exist in both a and b
-- Returned results:
2
Ответ 5
Мне также нравится использовать NOT EXISTS. Когда дело доходит до производительности, если индекс правильно, он должен работать так же, как LEFT JOIN или лучше. Плюс его легче читать.
SELECT Column1
FROM TableA a
WHERE NOT EXISTS ( SELECT Column1
FROM Tableb b
WHERE a.Column1 = b.Column1
)
Ответ 6
Это пример из реальной жизни, меня попросили предоставить список пользователей, которые покупались с нашего сайта за последние 6 месяцев, но не в последние 3 месяца.
Для меня самый понятный способ, о котором я могу думать, такой:
--Users that bought from us 6 months ago and between 3 months ago.
DECLARE @6To3MonthsUsers table (UserID int,OrderDate datetime)
INSERT @6To3MonthsUsers
select u.ID,opd.OrderDate
from OrdersPaid opd
inner join Orders o
on opd.OrderID = o.ID
inner join Users u
on o.BuyerID = u.ID
where 1=1
and opd.OrderDate BETWEEN DATEADD(m,-6,GETDATE()) and DATEADD(m,-3,GETDATE())
--Users that bought from us in the last 3 months
DECLARE @Last3MonthsUsers table (UserID int,OrderDate datetime)
INSERT @Last3MonthsUsers
select u.ID,opd.OrderDate
from OrdersPaid opd
inner join Orders o
on opd.OrderID = o.ID
inner join Users u
on o.BuyerID = u.ID
where 1=1
and opd.OrderDate BETWEEN DATEADD(m,-3,GETDATE()) and GETDATE()
Теперь, имея эти 2 таблицы в моих руках, мне нужно получить только пользователей из таблицы @6To3MonthsUsers, которые не находятся в таблице @Last3MonthsUsers.
Есть два простых способа добиться этого:
-
Использование Left Join:
select distinct a.UserID
from @6To3MonthsUsers a
left join @Last3MonthsUsers b
on a.UserID = b.UserID
where b.UserID is null
-
Не в:
select distinct a.UserID
from @6To3MonthsUsers a
where a.UserID not in (select b.UserID from @Last3MonthsUsers b)
Оба способа получат мне тот же результат, я лично предпочитаю второй способ, потому что он более читабельный.