SQL";“在子查询中”;当子查询可以为空时

SQL";“在子查询中”;当子查询可以为空时,sql,ruby-on-rails,sqlite,postgresql,arel,Sql,Ruby On Rails,Sqlite,Postgresql,Arel,我有一个查询,需要返回子查询中不匹配的结果。子查询可以返回一个空结果,因此如果子查询返回一个空集,我需要设置一个默认值(比如0),以防止IN(NULL)总是返回另一个NULL 比如说 SELECT * FROM example_table WHERE id NOT IN (subquery_that_selects_ids) 选择ID的子查询可以返回一组整数,即(1,2,5,6) 如果子查询未找到匹配结果,则返回一个空集 COALESCE在这里不起作用,因为子查询可能会返回多个结果 解决方案需

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

比如说

SELECT * FROM example_table WHERE id NOT IN (subquery_that_selects_ids)
选择ID的子查询可以返回一组整数,即(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(其他条件)
计算为
[]
时,
被替换为
NULL

因此,我将查询重新编写为:

Object.where("id NOT IN (" + Object.where(other_conditions).select(:id).to_sql + ")")
问题解决了


我要赞扬@Michael Buen,但也要投票给任何告诉我这个问题的人,因为他们是正确的。特别感谢@OMG Ponies和@Ted Elliott

为什么这不起作用

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

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
尝试:


我认为这有点复杂,即使子查询中并没有行,也并没有行。您的查询将在不修改的情况下工作。无论如何,如果确实希望子查询在不满足条件的情况下生成行,请使用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保留重复

我想你有点混淆了。如果选择ID的子查询返回一个空集(因此选择了示例表中的每一行),那么您发布的查询就可以正常工作。这里不涉及隐式空值

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

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

如果使用NOT in运算符,并且子查询返回的集合包含空值,则在多值子查询上会出现问题。如果子查询是一个空集,这并不意味着它返回null;)

在包含空值的情况下,它会强制外部查询返回一个空集,因为它无法说明该值是否处于未知状态

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

*选择姓氏 来自人力资源部员工 其中佣金百分比不在(0.1,0.35)*

此查询将返回26行

*选择姓氏 来自人力资源部员工 其中佣金不在(0.1,0.35,空)*

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

希望这有帮助

谢谢


Alexander Bufalo

你能发布一些示例数据和一个真正的子查询吗?我不清楚如何从子查询返回NULL,除非您为它指定了条件。子查询不应该返回任何记录,不是NULL,不是吗?无论子查询返回NULL还是没有记录,“id IN(subquery\u which\u selects\u id)”子句都将是NULL或false,这将导致主查询不返回任何记录。这不是期望的结果吗?您的权利,不是NULL,而是一个空集[],它在not IN时似乎被视为NULL。Elliott,当子查询返回一个空集时,期望的结果是主查询返回它的所有结果。我想您让它复杂了一点,即使子查询中没有行,NOT IN也将有行。您的查询将在不进行修改的情况下工作,这在我的情况下不起作用,因为没有可选择的内容,因此也没有可合并的内容。在子选择中怎么可能没有可选择的内容?问题不是子查询的结果中有空值,而是整个子查询是一个空集,因此,从子查询中选择x.id,如果子查询选择x.id作为x,其中x.id不为null,则仍将返回一个空集。
SELECT * FROM example_table WHERE id = (SELECT id FROM other_table WHERE name = 'foo')