2010-02-04 9 views
31

mam DołączSQL Inner Join Na wartości NULL

SELECT * FROM Y 
INNER JOIN X ON ISNULL(X.QID, 0) = ISNULL(y.QID, 0) 

Isnull w Join jak to sprawia, że ​​powolna. To tak jakby mieć warunkowe dołączenie. Czy jest coś takiego na coś takiego? mam wiele rekordów gdzie QID jest Null

Każdy ma pracę wokół, że nie pociąga za sobą modyfikację danych

+2

Dla jakiej bazy danych (w tym wersji)? –

+0

Tylko SQL Server i Access mają 'ISNULL()', więc zakładam, że SQL Server –

+0

Baza danych: sql 2005 – Rico

Odpowiedz

50

Masz dwie opcje

INNER JOIN x ON x.qid = y.qid OR (x.qid IS NULL AND y.qid IS NULL)

lub łatwiejszych

INNER JOIN x ON x.qid IS NOT DISTINCT FROM y.qid

+0

, który działa szybciej? – Rico

+0

Oczywiście, 'IS NOT DISTINCT FROM' nie może być wolniejszy, więc pójdę z nim. Ale żadna z nich nie powinna być/spowolnić /. Musiałbyś mówić o dość masowym zestawie danych, żeby to miało znaczenie. –

+0

hmm evan jak możesz prawdopodobnie zrozumieć, że jest to mniejsza wersja o wiele większy widok. Jak już oświadczyłeś, to, co pokazano powyżej, jest nowicjuszem, który mi przeszkadza. Chociaż nie chcę wywietrzyć mojego widoku w każdym miejscu, może minutę na to przyjrzeć i pomóc mi załatać ranę ... – Rico

-1

Zasadniczo chcesz j oin dwie tabele razem, gdzie ich kolumny QID są zarówno zerowe, poprawne, jak i nie są Jednak nie egzekwujesz żadnych innych warunków, takich jak dwie wartości QID (co wydaje mi się dziwne, ale w porządku). Coś tak prostego jak poniżej (przetestowane w MySQL) wydaje się robić to, co chcesz:

SELECT * FROM `Y` INNER JOIN `X` ON (`Y`.`QID` IS NOT NULL AND `X`.`QID` IS NOT NULL); 

To daje każdą niezerową wiersz Y dołączył do każdego niepuste rzędu w X.

aktualizacja: Rico mówi, że chce również wiersze z wartościami NULL, to dlaczego nie po prostu:

SELECT * FROM `Y` INNER JOIN `X`; 
+0

To jest niepoprawne .. jeśli jest to y.qid = x.qid, to dostarczy mi tylko wiersze, które nie są zerowe. Chcę wiersze, w których są one zarówno zerowe jak i. – Rico

+0

Ok, nie było to dla mnie jasne. – pr1001

+0

Pozwól mi zobaczyć, czy mogę wymyślić dokładniejszy przykład, aby usunąć problemy – Rico

8

Czy stawia sobie za pomocą sprzężenia wewnętrznego składni?

Jeśli nie można użyć tej alternatywnej składni:

SELECT * 
FROM Y,X 
WHERE (X.QID=Y.QID) or (X.QUID is null and Y.QUID is null) 
+1

Nie ma żadnej korzyści z używania tej składni, a nie jawnego przyłączenia się w zaakceptowanej odpowiedzi. –

3

jestem całkiem pewny, że przyłączyć nawet nie robić, co chcesz. Jeśli w tabeli a z zerowym qid i 100 rekordów w tabeli b z zerowym znakiem qid znajduje się 100 rekordów, to połączenie powinno zostać wykonane w formie połączenia krzyżowego i dać 10 000 wyników dla tych rekordów. Jeśli spojrzeć na poniższy kod i uruchomić przykłady, myślę, że ostatni z nich jest prawdopodobnie bardziej wynikiem ustawić zamierzałeś:

create table #test1 (id int identity, qid int) 
create table #test2 (id int identity, qid int) 

Insert #test1 (qid) 
select null 
union all 
select null 
union all 
select 1 
union all 
select 2 
union all 
select null 

Insert #test2 (qid) 
select null 
union all 
select null 
union all 
select 1 
union all 
select 3 
union all 
select null 


select * from #test2 t2 
join #test1 t1 on t2.qid = t1.qid 

select * from #test2 t2 
join #test1 t1 on isnull(t2.qid, 0) = isnull(t1.qid, 0) 


select * from #test2 t2 
join #test1 t1 on 
t1.qid = t2.qid OR (t1.qid IS NULL AND t2.qid IS NULL) 


select t2.id, t2.qid, t1.id, t1.qid from #test2 t2 
join #test1 t1 on t2.qid = t1.qid 
union all 
select null, null,id, qid from #test1 where qid is null 
union all 
select id, qid, null, null from #test2 where qid is null 
+0

Moje bieżące połączenie wykonuje to, co chcę, po prostu robi to sprawnie. – Rico

+0

Z ciekawości, dlaczego chcesz połączyć krzyż na identyfikatorach null? – HLGEM

1

Jeśli chcesz wartości null, które należy uwzględnić z Y.QID następnie Najszybszym sposobem jest

SELECT * FROM Y LEFT JOIN X ON y.QID = X.QID

Uwaga: to rozwiązanie jest stosowane tylko wtedy, gdy trzeba wartości null z lewej tabeli tj Y (w powyższym przypadku).

Inaczej INNER JOIN x ON x.qid IS NOT DISTINCT FROM y.qid jest właściwy sposób zrobić

-1

Można również użyć funkcji coalesce. Przetestowałem to w PostgreSQL, ale powinno również działać dla MySQL lub MS SQL server.

INNER JOIN x ON coalesce(x.qid, -1) = coalesce(y.qid, -1) 

ten zastąpi NULL z -1 przed oceniając go.Dlatego nie musi być żadnego -1 w qid.

5

This article has a good discussion on this issue. Można użyć:

SELECT * 
FROM Y 
INNER JOIN X ON EXISTS(SELECT X.QID 
         INTERSECT 
         SELECT y.QID); 
+0

Jakiekolwiek porównanie planów kwerend w tym porównaniu z 'ISNULL()'? Nie mogłem zauważyć dużej różnicy w przykładowym zestawie danych, ale podoba mi się prostota łączenia w wielu kolumnach. –

+0

@ThomasG.Mayfield - 'ISNULL' zabija użycie indeksu. na przykład porównaj plany dla 'CREATE TABLE #T (X INT UNIQUE); SELECT * FROM #T T1 WEWNĘTRZNY DOŁĄCZ DOŁĄCZ #T T2 ZA DARMO (WYBIERZ WYBÓR T1.X WYB. T2.X); WYBIERZ * Z # T T1 WEJŚCIE DOŁĄCZ DOŁĄCZ #T T2 WŁ. ISNULL (T1.X, -1) = ISNULL (T2.X, -1); WYBIERZ * Z # T T1 WEWNĘTRZNA PĘTLA DOŁĄCZ #T T2 NA ISTNIEJĄCĘ (WYBIERZ T1.X WYBÓR PRZESYŁANIA T2.X); WYBIERZ * Z # T T1 PĘTLA WEWNĘTRZNA DOŁĄCZ #T T2 WŁ. ISNULL (T1.X, -1) = ISNULL (T2.X, -1); DROP TABLE # T' - wersja scalona nie może używać kolejności indeksowania i potrzebuje sortowania, a zagnieżdżone pętle skanują dane wejściowe, zamiast je wyszukiwać . –

+0

Przez cały czas używałam tej sztuczki, ale wygląda na to, że optymalizator programu SQL Server 2016 nie lubi tego zbytnio. Muszę to jednak dokładniej zbadać, –