当子查询可以为NULL时,SQL“IN子查询”

时间:2010-12-20 03:05:15

标签: sql ruby-on-rails sqlite postgresql arel

我有一个查询需要返回子查询中不匹配的结果。子查询可以返回一个空结果,所以如果子查询返回一个空集来阻止IN (NULL)总是返回另一个NULL,我需要设置一个默认值(比如说0)。

例如

SELECT * FROM example_table WHERE id NOT IN (subquery_that_selects_ids)

subquery_that_selects_ids可以返回一组整数,即(1,2,5,6) 如果子查询没有找到匹配的结果,则为空集。

COALESCE在这里不起作用,因为子查询可能会返回多个结果。

解决方案需要在SQLite或postgresql中运行。 如何防止子查询返回空集?


每个人都在告诉我查询应该按照书面形式运行。你们都是正确的。该查询是由Rails3的AREL构建的,因为我在这里发布了完整的查询,我注意到AREL在使用数组条件时将NULL置为空集。

即。我在rails中的查询看起来像:

Object.where("id NOT IN (?)", Object.where(other_conditions).select(:id))

Object.where(other_conditions)评估为[]后,?NULL替换

所以我重新编写查询看起来像:

Object.where("id NOT IN (" + Object.where(other_conditions).select(:id).to_sql + ")")

问题解决了。

我赞扬@Michael Buen,但也支持任何告诉我查询将按照书面形式工作的人,因为它们是正确的。特别感谢@OMG小马和@Ted Elliott!

5 个答案:

答案 0 :(得分:5)

尝试:

SELECT * FROM example_table 
WHERE id NOT 
    IN (select x.id from subquery_that_selects_ids as x where x.id is not null)

我认为你有点复杂,即使在子查询中没有行,NOT IN也会有行。您的查询无需修改即可运行。无论如何,如果你真的希望你的子查询产生行,即使条件不满足,也可以使用UNION

SELECT * FROM example_table 
WHERE id NOT 
    IN (select x.id from subquery_that_selects_ids as x 
        where 1 = 0 -- empty set
        union
        select 0)

UNION无论如何都会消除重复,UNION ALL保留重复

答案 1 :(得分:2)

怎么样:

SELECT ex.ID, ex.OtherFields
FROM ExampleTable ex left join (Select ID from SomeOtherTable) o on o.ID = ex.ID
WHERE o.ID is null

答案 2 :(得分:2)

我觉得你很困惑。如果subquery_that_selects_ids返回一个空集,那么您发布的查询就可以正常工作(因此选择example_table中的每一行)。这里没有涉及隐式空值。

您可能正在考虑使用子查询作为标量的情况。在这种情况下,如果子查询没有返回任何行,则结果值为null,例如

SELECT * FROM example_table WHERE id = (SELECT id FROM other_table WHERE name = 'foo')

答案 3 :(得分:0)

为什么这不起作用?

SELECT *
  FROM example_table
 WHERE id IN (
    SELECT COALESCE(id, 0)
      FROM another_example_table
);

答案 4 :(得分:0)

如果使用NOT in运算符并且子查询返回的集包含NULL值,则多值子查询将出现问题。如果子查询是空集,那并不意味着它返回null;)

在包含空值的情况下,它会强制外部查询返回一个空集,因为它无法说明该值是UNKNOWN还是NOT IN Unknown。

以下是使用 hr.employees表的一个示例。

* SELECT last_name 来自hr.employees 佣金佣金不在(0.1,0.35); *

此查询将返回26行。

* SELECT last_name 来自hr.employees WHERE commission_pct NOT IN(0.1,0.35,NULL); *

此查询不返回任何行,因为传递给NOT IN的列表中的NULL将破坏它。因此,如果您的子查询可能返回任何空值,则应使用子查询中的函数(NVL,NVL2,COALESCE)对其进行处理。

希望这会有所帮助。

由于

Alexander Bufalo