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)
    

Оба способа получат мне тот же результат, я лично предпочитаю второй способ, потому что он более читабельный.