处理空值的最优雅方法是啥

Posted

技术标签:

【中文标题】处理空值的最优雅方法是啥【英文标题】:What's the most elegant way to deal with nulls处理空值的最优雅方法是什么 【发布时间】:2014-01-02 09:54:29 【问题描述】:

我有两个表和一个如下所示的查询::

select * from table_1
where x.column_1 in (
    select column_2 from table_2
    where column_3 = 'foo')

这几乎对我有用; column_1column_2 中有空值,我希望将其视为匹配项。

我可以用这个写一个union

-- query above
union all
select * from table_1
where column_2 is null
and exists (select * from table_2
    where column_3 = 'foo'
    and column_2 is null)

但是会扫描每个表两次,这似乎效率低下。

有没有办法将这两个查询结合起来进行高效查询?

【问题讨论】:

哪个 RDBMS,任何或特定实例? 【参考方案1】:

试试这个

select * from table_1
where coalesce (column_1,'special value') in 
      (
        select coalesce (column_2,'special value') 
          from table_2
         where column_3 = 'foo'
      )

当然'special value'不应包含在table_2column_3中,并且必须与列的数据类型兼容。

【讨论】:

如果数据中没有不能出现的'special value'怎么办? 该死,我就知道会有人指出那个。思考。首先,我在最后一句话中缩小了我的想法。第二:您多久拥有可能(并且确实)包含所有可能值的可空列?但是,我添加了完整的解决方案。【参考方案2】:

这不适合你吗?

select  *   
from    table_1 t1
where   EXISTS (
                    select  1
                    from    table_2 t2
                    where   t2.column_3 = 'foo'
                    AND     (
                                    t1.column_1 = t2.column_2
                                OR  (t1.column_1 IS NULL AND t2.column_2 IS NULL)
                            )
                )

这将包括它们相等或都为 NULL 的地方。

我避免ISNULL, IFNULL, COALESCE 的原因是正如@alzaimar 所说,数据类型和特殊值 问题

编辑

正如@ypercube 所提到的,对于 mysql,这可以简化为

select  *   
from    table_1 t1
where   EXISTS (
                    select  1
                    from    table_2 t2
                    where   t2.column_3 = 'foo'
                    AND     t1.column_1 <=> t2.column_2                
                 )

【讨论】:

那是关联子查询,效率会很低 但它是 100% 正确的。我的尝试进行了全面扫描(我想),但它真的没有比这更无效的了。 您可以使用(mysql) &lt;=&gt; operator 将条件简化为:AND t1.column_1 &lt;=&gt; t2.column_2 @Bohemian 这个查询会比你接受的那个更有效率。 @ypercube 你确定吗?不会对 table1 中的每一行执行一次内部查询?您是说优化器将其转换为联接?【参考方案3】:

试试这个

select T.* from table_1 T

LEFT JOIN table_2 S ON T.column_1 = S.column_2 OR NULLIF(T.column_1,NULL) = NULLIF(S.column_2 ,NULL)

where column_3 = 'foo'

【讨论】:

但是使用=的空值不会匹配 @Bohemian 试试&lt;=&gt;【参考方案4】:

试试这个:

SELECT * 
FROM   table_1 t1 
       INNER JOIN table_2 t2 
               ON t1.column_1 = t2.column_2 
WHERE  t2.column_3 = 'foo' 
       AND t1.column_2 IS NULL 
       AND t2.column_2 IS NULL 

【讨论】:

(错字:倒数第二行应该有 column_1。)这不起作用: 1. JOIN ON 将不包括 t1.column_1 或 t1.column_2 为空的行,那么 WHERE 将只过滤结果,丢失空匹配。 2. IS NULL 的 AND 必须是 ORed(不是 ANDed)。(每 1,进入 ON。) 3. 这从两个表返回 * 而不仅仅是 table_1。

以上是关于处理空值的最优雅方法是啥的主要内容,如果未能解决你的问题,请参考以下文章

匠人手法 - 优雅的处理空值

检索 MySQL 表注释的最优雅方法是啥?

老大难的空指针,如何优雅处理?

在 Silverlight 的 SaveFileDialog 中缺少 DefaultFileName 的最优雅的解决方法是啥?

在 C# List 中查找重复项索引的最优雅方法是啥

找到满足某些条件的 16 位数字的最优雅方法是啥?