SQL Server JOIN fehlende NULL-Werte


74

Angenommen, ich hätte die folgenden 2 Tabellen:

      Table1:                                Table2:
Col1:      Col2:     Col3:             Col1:       Col2:       Col4:
a          b         c                 a           b           d
e          <null>    f                 e           <null>      g
h          i         j                 h           i           k
l          <null>    m                 l           <null>      n
o          <null>    p                 o           <null>      q

Jetzt möchte ich diese Tabellen verbinden Col1und Col2das gesamte Set so zurückbringen, dass es so aussieht:

     Result:
Col1:      Col2:     Col3:     Col4:
a          b         c         d
e          <null>    f         g
h          i         j         k
l          <null>    m         n
o          <null>    p         q

Also habe ich ein SQL wie folgt ausprobiert:

SELECT Table1.Col1, Table1.Col2, Table1.Col3, Table2.Col4
FROM Table1 INNER JOIN Table2
ON Table1.Col1 = Table2.Col1 
AND Table1.Col2 = Table2.Col2

Aber es stimmt nicht mit den NULLWerten in überein Col2, so dass ich am Ende Folgendes habe:

     Result:
Col1:      Col2:     Col3:     Col4:
a          b         c         d
h          i         j         k

Wie kann ich das gewünschte Ergebnis erzielen?

Vielen Dank!


Ist das spezifisch für SQL Server? Ich kann nicht scheinen, dies in Postgres 11.5
Daniel Lizik

Antworten:


104

Sie können die Verknüpfungen explizit angeben:

SELECT Table1.Col1, Table1.Col2, Table1.Col3, Table2.Col4
FROM Table1 INNER JOIN
     Table2
      ON (Table1.Col1 = Table2.Col1 or Table1.Col1 is NULL and Table2.Col1 is NULL) AND
         (Table1.Col2 = Table2.Col2 or Table1.Col2 is NULL and Table2.Col2 is NULL)

In der Praxis würde ich eher coalesce()die Join-Bedingung verwenden:

SELECT Table1.Col1, Table1.Col2, Table1.Col3, Table2.Col4
FROM Table1 INNER JOIN
     Table2
     ON (coalesce(Table1.Col1, '') = coalesce(Table2.Col1, '')) AND
        (coalesce(Table1.Col2, '') = coalesce(Table2.Col2, ''))

Wo ''wäre ein Wert nicht in einer der Tabellen.

Nur ein Wort der Vorsicht. In den meisten Datenbanken verhindert die Verwendung eines dieser Konstrukte die Verwendung von Indizes.


2
Eine andere Option für die Verschmelzung wäreON (T1.C1=T2.C1 or (coalesce(T1.C1,T2.C1) is null)) and (T1.C2=T2.C2 or (coalesce(T1.C2,T2.C2) is null))
mpag

Dies funktioniert nicht, wenn Sie haben Table1=(a,b,c)(a,null,d) Table2=(a,b,e). In diesem Fall stimmt der Join mit dem Fall Table1(a,null,d)mit dem nicht vorhandenen Fall überein Table2(a,null,null). Dies sollte nicht zu einer Übereinstimmung führen.
Tripp Kinetics

Mit anderen Worten, dies unterscheidet nicht zwischen Fällen, NULLin Table2.Col2denen es Übereinstimmungen gibt, und Fällen, in denen überhaupt keine Aufzeichnungen vorliegen Table2.
Tripp Kinetics

37

Verwenden Sie Left Outer Join anstelle von Inner Join, um Zeilen mit NULLS einzuschließen.

SELECT Table1.Col1, Table1.Col2, Table1.Col3, Table2.Col4
FROM Table1 LEFT OUTER JOIN 
    Table2 ON Table1.Col1 = Table2.Col1 
    AND Table1.Col2 = Table2.Col2

Weitere Informationen finden Sie hier: http://technet.microsoft.com/en-us/library/ms190409(v=sql.105).aspx


Funktioniert bei mir. Einfach und sauber.
Kuvalya

7
Dies beantwortet nicht die ursprüngliche Frage. Ihre Lösung enthält Nullzeilen für Tabelle2, wenn keine Übereinstimmung gefunden wird. Schauen Sie sich die zweite Zeile in beiden Tabellen in OPs Frage an
AaA

1
Dies löst die Frage nicht wirklich, da Sie jetzt filtern müssen, um die gewünschten Werte auszuwählen. Dazu müssen Sie sich erneut mit den Nullen auseinandersetzen.
Jamie Marshall

1
Danke für den guten Rat, das habe ich gebraucht. Mein Fall war Table.Col1 war null und es gab überhaupt keinen Null-Datensatz in Tabelle2, daher wurde diese Zeile mit null col überhaupt nicht ausgewählt.
Davit Mikuchadze

17

Versuchen Sie es mit der ISNULLFunktion:

SELECT Table1.Col1, Table1.Col2, Table1.Col3, Table2.Col4
FROM Table1 
INNER JOIN Table2
   ON Table1.Col1 = Table2.Col1 
   AND ISNULL(Table1.Col2, 'ZZZZ') = ISNULL(Table2.Col2,'ZZZZ')

Wo 'ZZZZ'ist ein beliebiger Wert nie in der Tabelle.


6
Dies führt magische Werte ein, die ich eher vermeide, wenn es nicht unbedingt notwendig ist
lc.

Dies würde gut funktionieren, setzt jedoch voraus, dass '0' an keiner anderen Stelle in einer anderen Zeile verwendet wird.
PinnyM

Ja, ich bevorzuge die Antwort von @ Gordon und biete nur eine Alternative an. Und ich würde wahrscheinlich einen anderen Wert verwenden, von dem ich wusste, dass er nicht in den Rückgabewerten wie 'ZZZZ' oder so dargestellt werden kann :-)
sgeddes

Dies unterscheidet nicht zwischen Fällen, in Table2.Col2 IS NULLdenen kein übereinstimmender Datensatz vorhanden ist Table2.
Tripp Kinetics

11

Schmutziger und schneller Hack:

SELECT Table1.Col1, Table1.Col2, Table1.Col3, Table2.Col4
FROM Table1 INNER JOIN Table2 ON Table1.Col1 = Table2.Col1
 AND ((Table1.Col2 = Table2.Col2) OR (Table1.Col2 IS NULL AND Table2.Col2 IS NULL))

Danke, @Jap - Genau das, wonach ich gesucht habe ... Gordon hat dich geschlagen, aber danke, dass du darauf geantwortet hast!
John Bustos

1

Sie können einfach so abbilden

select * from tableA a
join tableB b on isnull(a.colID,'') = isnull(b.colId,'')

1

Aus irgendeinem Grund konnte ich es nicht dazu bringen, mit dem äußeren Join zu arbeiten.

Also habe ich verwendet:

SELECT * from t1 where not Id in (SELECT DISTINCT t2.id from t2)

0

Die einzig richtige Antwort besteht darin, keine Spalten mit Nullwerten zu verbinden. Dies kann sehr schnell zu unerwünschtem Verhalten führen.

zB isnull (b.colId, ''): Was passiert, wenn Ihre Daten leere Zeichenfolgen enthalten? Der Join kann doppelte Zeilen enthalten, was in diesem Fall vermutlich nicht beabsichtigt ist.


-1

Versuchen Sie, eine zusätzliche Bedingung in join zu verwenden:

SELECT Table1.Col1, Table1.Col2, Table1.Col3, Table2.Col4
FROM Table1 
INNER JOIN Table2
ON (Table1.Col1 = Table2.Col1 
    OR (Table1.Col1 IS NULL AND Table2.Col1 IS NULL)
   )
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.