【问题标题】:SQL Server JOIN missing NULL valuesSQL Server JOIN 缺少 NULL 值
【发布时间】:2013-01-16 19:15:57
【问题描述】:

假设我有以下 2 个表:

      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

但它与Col2 中的NULL 值不匹配,所以我最终得到:

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

我怎样才能得到我想要的结果??

谢谢!

【问题讨论】:

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

标签: sql sql-server


【解决方案1】:

您可以明确说明连接:

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

其中'' 是任何一个表中都不存在的值。

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

【讨论】:

  • 合并的另一个选项是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))
  • 这在您拥有Table1=(a,b,c)(a,null,d) Table2=(a,b,e) 的情况下不起作用。在这种情况下,连接将Table1(a,null,d) 与不存在的Table2(a,null,null) 匹配。这不应该导致匹配。
  • 换句话说,这不能区分Table2.Col2 中存在匹配的NULLTable2 中根本没有记录的情况。
  • 不应该像下面这样在 or 运算符之后将空检查作为单个单元加入条件。 (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))
【解决方案2】:

使用左外连接而不是内连接来包含带有 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/en-us/library/ms190409(v=sql.105).aspx

【讨论】:

  • 为我工作。简单干净。
  • 这没有回答原始问题。如果未找到匹配项,您的解决方案将包括 table2 的空行。查看 OP 问题中两个表格的第二行
  • 这并不能真正解决问题,因为您现在必须过滤以选择所需的值。为此,您将不得不再次与空值抗衡。
  • 感谢您的好建议,这正是我所需要的。我的情况是 Table.Col1 为 null 并且 Table2 中根本没有 null 记录,所以根本没有选择带有 null col 的行。
【解决方案3】:

尝试使用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' 是表中从未出现过的任意值。

【讨论】:

  • 这引入了魔法值,除非绝对必要,否则我倾向于避免使用这些值
  • 这会很好地工作,但假设'0'没有在另一行的其他地方使用。
  • 是的,我更喜欢@Gordon 的回复,只是提供了一个替代方案。而且我可能会使用我知道无法在返回值中表示的不同值,例如“ZZZZ”之类的:-)
  • 这不区分Table2.Col2 IS NULLTable2 中没有匹配记录的情况。
【解决方案4】:

肮脏而快速的破解:

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 打败了你,但感谢您回答这个问题!
  • 这个解决方案既不脏也不黑。这只是在 T-SQL 中执行此操作的正确方法。
【解决方案5】:

你可以这样映射

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

【讨论】:

  • 这是有问题的,因为它不区分空字符串和实际的 NULL 值。如果 a.colD 为空字符串且 b.colID 为 NULL,则比较仍将评估为 true,即使两列包含不同的值。在某些情况下,您不想将 NULL 和空字符串视为相等。
【解决方案6】:

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

所以我用了:

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

【讨论】:

    【解决方案7】:

    尝试在连接中使用附加条件:

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

    【讨论】:

      【解决方案8】:

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

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

      【讨论】:

      • 我不同意。正确的答案不是避免加入可为空的列。正确的答案是正确地在 JOIN 中进行比较(如本问题的其他答案所示)。
      • 大卫你说得对,但我认为我们可以同意 ISNULL 解决方案确实是一种不好的做法。
      • 是的,ISNULL 解决方案不是一个好主意。使用魔法值通常是有问题的,尤其是在这种情况下。在这种情况下使用 ISNULL 既不必要也不可取。 NULL 在 T-SQL 中确实有特殊含义。这意味着该值为未知。这与任何其他可能的值都非常不同。因此,SQL Server 对待 NULL 的方式与任何其他值非常不同,通常不应尝试将 NULL 视为与任何其他值相同。
      【解决方案9】:
      declare @Table1 as Table(Col1 varchar(1),Col2 varchar(1), Col3 varchar(1))
      declare @Table2 as Table(Col1 varchar(1),Col2 varchar(1), Col4 varchar(1))
      insert into @Table1
      values('a',          'b',     'c'),
      ('e',          null,    'f'), 
      ('h',          'i'  ,   'j'), 
      ('l',          null  ,  'm'), 
      ('o',          null  ,  'p') 
      insert into @Table2
      values('a',          'b',     'd'),
      ('e',          null,    'g'), 
      ('h',          'i'  ,   'k'), 
      ('l',          null  ,  'n'), 
      ('o',          null  ,  'q') 
      
      
      select * from @Table1 tbl1
      join @Table2 tbl2
      on tbl1.Col1 =tbl2.Col1
      and isnull(tbl1.Col2,0) =isnull(tbl2.Col2,0)
      

      输出:

       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
      

      【讨论】:

        【解决方案10】:

        一些 SQL 实现有一个特殊的 Null 安全相等运算符。

        例如 Snowflake 有 EQUAL_NULL 所以你可以这样做

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-12-14
          • 2019-06-20
          相关资源
          最近更新 更多