【问题标题】:inner join on null value空值内连接
【发布时间】:2010-01-23 11:41:55
【问题描述】:

我不确定我是否在逻辑上犯了错误。

如果我有一个查询并且我使用空值进行内部联接,我会始终得不到任何结果,还是会忽略联接并成功?例子

user { id PK, name NVARCHAR NOT NULL, banStatus nullable reference }

如果我写了 u.banStatus 我将不会收到任何行?

select * from user as u
join banstatus as b on u.banStatus=b.id
where id=1

【问题讨论】:

  • NULL 是未定义的,所以如果我们有 NULL = NULL 那么结果将始终为假,因为我们正在比较两个未定义的值。我希望它能回答你的问题
  • 您的查询也有错误。 where 子句中的 id 字段不明确 - 它可能是 u.idb.id
  • @Mark 我尝试了一个更复杂的逻辑版本,并怀疑这个问题。因此编写该虚拟查询并没有意识到歧义

标签: sql mysql tsql sqlite


【解决方案1】:

如果连接为空,则不会得到该行,因为 NULL 不能等于任何值,即使是 NULL。

如果您将其更改为 LEFT JOIN,那么您将获得该行。

使用内部连接:

select * from user as u
join banstatus as b on u.banStatus=b.id

1, '1', 1, 'Banned'

左连接:

select * from user as u
left join banstatus as b on u.banStatus=b.id

1, '1', 1, 'Banned'
2, 'NULL', , ''

使用此测试数据:

CREATE TABLE user (id int, banstatus nvarchar(100));
INSERT INTO user (id, banstatus) VALUES
(1, '1'),
(2, 'NULL');

CREATE TABLE banstatus (id int, text nvarchar(100));
INSERT INTO banstatus (id, text) VALUES
(1, 'Banned');

【讨论】:

  • 我不需要测试数据或除构象之外的任何其他内容(是的,您不会得到行),但对未来的读者有好处。 +1&接受。
【解决方案2】:

当您执行INNER JOIN 时,NULL 值不匹配任何内容。甚至彼此都没有。这就是您的查询没有返回任何行的原因。 (Source)

【讨论】:

    【解决方案3】:

    这是一个空值内连接(Oracle 语法):

    select *
      from user
           uu
      join banstatus
           bb
        on uu.banstatus = bb.id
           or
           uu.banstatus is null and bb.id is null
    

    【讨论】:

    • 所以当 user 和 bb 为空时加入?有趣的。 id 永远不会是 null 或 0。如果我写了 on uu.banstatus = bb.id or uu.banstatus is null 它会忽略它并加入而不给我 0 行?这和左连接一样吗?有趣的。我不再需要答案,但如果您愿意,我会阅读。
    • 不,这不像左连接。如果bb.id 永远不会为空,则结果中不会有空行uu.banstatus
    • 我知道这已经很晚了,但我建议在“或”子句周围使用括号。
    • andor 的优先级明确,前者更高。我更喜欢由于避免不必要的语法而产生的更高的信噪比。作为一个原则问题,我永远不会写1 + (2 * 3) 来澄清我所说的1 + 2 * 3 的意思,因为有朝一日没有基本算术知识的人可能会尝试理解我的代码。小说家不会为了让外国读者更容易理解他们的作品而简化他们的散文。同样,我不应该为了让懒得学习 SQL 的人受益而简化我的代码。
    • @KeithL,作为妥协,我调整了缩进以阐明意图。
    【解决方案4】:

    空值不等于任何其他值,因此空值的连接条件不成立。您可以通过选择不同的连接条件来获得所需的结果。而不是

    u.banStatus = b.id
    

    使用

    u.banStatus = b.id OR (u.banStatus IS NULL AND b.id IS NULL)
    

    一些 SQL 方言对这种比较有更简洁的语法:

    -- PostgreSQL
    u.banStatus IS NOT DISTINCT FROM b.id
    
    -- SQLite
    u.banStatus IS b.id
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-13
      • 2017-05-19
      • 2012-05-04
      • 2018-11-30
      • 2014-04-29
      • 1970-01-01
      • 2017-04-09
      • 1970-01-01
      相关资源
      最近更新 更多