SQL Server JOIN缺少NULL值


75

假设我有以下两个表:

      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

现在,我想加入这些表Col1Col2然后将整个集合恢复为:

     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

因此,我尝试了类似的SQL:

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

但这与中的NULL值不匹配Col2,因此我最终得到:

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

我如何获得想要的结果?

谢谢!


这是特定于sql-server吗?我似乎无法在postgres 11.5中做到这一点
Daniel Lizik

Answers:


106

您可以明确地了解联接:

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)

在实践中,我将更有可能coalesce()在联接条件中使用:

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, ''))

''两个表中都不存在的值在哪里。

请注意。在大多数数据库中,使用任何这些构造都会阻止使用索引。


2
合并的另一个选择是ON (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

如果您有,这是行不通的Table1=(a,b,c)(a,null,d) Table2=(a,b,e)。在这种情况下,联接将大小写Table1(a,null,d)与不存在的case匹配Table2(a,null,null)。这不应导致匹配。
Tripp Kinetics

换句话说,这并不情况之间,那里是一个区别NULLTable2.Col2哪比赛,与所有中没有记录Table2
Tripp Kinetics

39

使用左外部联接而不是内部联接来包含具有NULLS的行。

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

有关更多信息,请参见此处:http : //technet.microsoft.com/zh-cn/library/ms190409(v=sql.105).aspx


为我工作。简单干净。
库瓦利亚

7
这不能回答原始问题。如果找不到匹配项,您的解决方案将为table2包含空行。在OP问题中查看两个表的第二行
AaA

1
这实际上并不能解决问题,因为您现在必须过滤以选择所需的值。为此,您将再次与null竞争。
杰米·马歇尔

1
感谢您的好建议,这就是我所需要的。我的情况是Table.Col1为空,并且Table2中根本没有空记录,因此根本不选择具有null col的行。
戴维特·米库查兹

17

尝试使用ISNULL功能:

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

'ZZZZ'在表中从未有的任意值。


6
这引入了除非绝对必要,否则我会避免的魔术值
lc。

这将很好地工作,但是假定在另一行的其他地方未使用“ 0”。
PinnyM 2013年

是的,我更喜欢@Gordon的回复,只是提供了另一种选择。而且我可能会使用一个我无法在诸如“ ZZZZ”之类的返回值中表示的其他值:-)
sgeddes 2013年

这无法区分的情况Table2.Col2 IS NULL和中没有匹配记录的情况Table2
Tripp Kinetics

11

肮脏又快速的破解:

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

谢谢@Jap-正是我想要的... Gordon击败了您,但感谢您回答!
John Bustos

1

你可以像这样映射

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

1

由于某种原因,我无法使其与外部联接一起使用。

所以我用了:

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

0

尝试在连接中使用其他条件:

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

0

唯一正确的答案是不要联接具有空值的列。这会很快导致不良行为。

例如,isnull(b.colId,''):如果数据中包含空字符串会怎样?联接可能重复行,我猜在这种情况下不打算这样做。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.