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?
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:
- A
cross join
jest najprostsza ze wszystkich. Implementuje tylko jedną logiczną fazę Przetwarzania zapytań, aCartesian 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. - 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 wierszefilters
oparte na predykacie określonym w klauzuliON
(znanej również jakoJoin condition
). -
NastÄ ™ pnie pojawia siÄ ™ trzeci typ zĹ ' Ä ... czenia,
Outer Joins
:W
outer join
, można oznaczyć tabelę jakopreserved
tabeli za pomocą słów kluczowychLEFT OUTER JOIN
,RIGHT OUTER JOIN
, lubFULL OUTER JOIN
pomiędzy nazwami tabel. NaOUTER
słowem kluczowym jestoptional
. Słowo kluczoweLEFT
oznacza, że wierszeleft table
są zachowane; słowo kluczoweRIGHT
oznacza, że wiersze wright table
są zachowane; a słowo kluczoweFULL
oznacza, że wiersze wboth
left
iright
} 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 predykatuON
. Ta faza dodaje te wiersze do tabeli wyników tworzy się przez dwie pierwsze fazy łączenia i używa znacznikówNULL
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.
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
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
)
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
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
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)
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ąć:
-
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
-
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.
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