Jak zwrócić wiersze z lewej tabeli nie Znalezione w prawej tabeli?

Mam dwie tabele o podobnych nazwach kolumn i muszę zwrócić rekordy z lewej tabeli, których nie ma w prawej tabeli? Mam klucz główny (kolumnę), który pomoże mi porównać obie tabele. Które połączenie jest preferowane?

Author: Dharman, 2014-09-05

7 answers

Jeśli prosisz o T-SQL, najpierw przyjrzyjmy się podstawom. Istnieją trzy rodzaje złączeń, każdy z własnym zestawem logicznych faz przetwarzania, jak:

  1. A cross join jest najprostsza ze wszystkich. Implementuje tylko jedną logiczną fazę Przetwarzania zapytań, a Cartesian Product. Faza ta działa na dwóch tablicach dostarczonych jako wejścia do połączenia i wytwarza iloczyn kartezjański z tych dwóch. Oznacza to, że każdy wiersz z jednego wejścia jest dopasowany do wszystkich wierszy z drugiego. Więc jeśli masz wiersze m w jednym tabela I n wierszy w drugim, otrzymasz m×n wierszy w wyniku.
  2. następnie są Inner joins: stosują dwie logiczne fazy Przetwarzania zapytań: A Cartesian product pomiędzy dwiema tabelami wejściowymi jak w połączeniu krzyżowym, a następnie wiersze filters oparte na predykacie określonym w klauzuli ON (znanej również jako Join condition).
  3. NastÄ ™ pnie pojawia siÄ ™ trzeci typ zĹ ' Ä ... czenia, Outer Joins:

    W outer join, można oznaczyć tabelę jako preserved tabeli za pomocą słów kluczowych LEFT OUTER JOIN, RIGHT OUTER JOIN, lub FULL OUTER JOIN pomiędzy nazwami tabel. Na OUTER słowem kluczowym jest optional. Słowo kluczowe LEFT oznacza, że wiersze left table są zachowane; słowo kluczowe RIGHT oznacza, że wiersze w right table są zachowane; a słowo kluczowe FULL oznacza, że wiersze w both left i right} są zachowane.

    Trzecia logiczna Faza Przetwarzania zapytań outer join identyfikuje wiersze z zachowanej tabeli, które nie znalazły dopasowania w drugiej tabeli na podstawie predykatu ON. Ta faza dodaje te wiersze do tabeli wyników tworzy się przez dwie pierwsze fazy łączenia i używa znaczników NULL jako elementów zastępczych dla atrybutów z nie reprezentowanej strony połączenia w tych zewnętrznych wierszach.

Teraz, jeśli spojrzymy na pytanie: aby zwrócić rekordy z lewej tabeli, które nie znajdują się w prawej tabeli, użyj Left outer join i odfiltruj wiersze z wartościami NULL dla atrybutów z prawej strony łącznika.

 49
Author: Deepshikha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-29 05:23:18

Spróbuj Tego

SELECT f.*
FROM first_table f LEFT JOIN second_table s ON f.key=s.key
WHERE s.key is NULL

Aby dowiedzieć się więcej przeczytaj ten artykuł: Joins in SQL Server

Tutaj wpisz opis obrazka

 81
Author: Shamseer K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-12 03:30:04

Lubię też używać NOT EXISTS. Jeśli chodzi o wydajność, jeśli indeks jest poprawny, powinien działać tak samo jak lewy łącznik lub lepiej. Plus jest łatwiejszy do odczytania.

SELECT Column1
FROM TableA a
WHERE NOT EXISTS ( SELECT Column1
                   FROM Tableb b
                   WHERE a.Column1 = b.Column1
                 )
 6
Author: viejoEngineer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-26 14:38:16

Nie mogę dodać nic poza przykładem kodu do pozostałych dwóch odpowiedzi: jednak uważam, że warto zobaczyć go w akcji(inne odpowiedzi, moim zdaniem, są lepsze, ponieważ wyjaśniają to).

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 
 2
Author: AHiggins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-05 13:02:09

Ta strona zawiera porządny podział różnych typów połączeń, a także wizualizacje diagramu Venna, aby pomóc... cóż... wizualizuj różnicę w połączeniach.

Jak mówili w komentarzach, jest to dość podstawowe zapytanie z dźwięków, więc powinieneś spróbować zrozumieć różnice między połączeniami i co one właściwie oznaczają.

Zobacz http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/

Szukasz zapytania takiego as:

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's 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
 1
Author: Kritner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-05 12:24:55

Select * from left table where key field not in (select key field from right table)

 1
Author: George Let,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-12 19:39:33

Jest to przykład z prawdziwej pracy, poproszono mnie o dostarczenie listy użytkowników, którzy kupili na naszej stronie w ciągu ostatnich 6 miesięcy, ale nie w ciągu ostatnich 3 miesięcy.

Dla mnie najbardziej zrozumiały sposób, jaki mogę wymyślić jest taki:

--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()

Teraz, z tymi 2 tabelami w moich rękach muszę uzyskać tylko użytkowników z tabeli @6to3monthsusers, których nie ma w @Last3MonthsUsers tabela.

Istnieją 2 proste sposoby, aby to osiągnąć:

  1. Za pomocą Left Join:

    select distinct a.UserID
    from @6To3MonthsUsers a
    left join @Last3MonthsUsers b
    on a.UserID = b.UserID
    where b.UserID is null
    
  2. Nie w:

    select distinct a.UserID
    from @6To3MonthsUsers a
    where a.UserID not in (select b.UserID from @Last3MonthsUsers b)
    

Oba sposoby dadzą mi ten sam wynik, osobiście wolę drugi sposób, ponieważ jest bardziej czytelny.

 0
Author: Offir Pe'er,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-03 08:28:39