У меня есть две таблицы с похожими именами столбцов, и мне нужно вернуть записи из левой таблицы, которые не найдены в правой таблице? У меня есть первичный ключ (столбец), который поможет мне сравнить обе таблицы. Какое соединение предпочтительнее?
SQL - Как вернуть строки из левой таблицы, не найденные в правой таблице?
Ответ 1
Если вы просите T-SQL, то сначала рассмотрите основы. Существует три типа объединений, каждый из которых имеет собственный набор фаз логической обработки, как:
- A
cross join
является самым простым. Он реализует только одну фазу обработки логических запросов - aCartesian 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
Ответ 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)
Оба способа получат мне тот же результат, я лично предпочитаю второй способ, потому что он более читабельный.