SQL WHERE语句,其中列可以是值或可以为NULL

时间:2013-08-09 22:22:22

标签: sql sqlite

我有一个SQL表(在SQLite3中),其中我试图聚合来自其他几个表的信息,并且一个表中的记录可能在另一个表中有或没有相应的记录。我的查询应该在聚合表中包含有和没有链接信息的记录。例如:

            CREATE TABLE all_households AS
                SELECT pop.uid AS pop_uid,
                       pop.surname,
                       pop.given,
                       pop.age,
                       pop.real_property,

                       farm.uid AS farm_uid,
                       farm.improved_acres,
                       farm.unimproved_acres,
                       farm.cash_value,
                       farm.corn,
                       farm.cotton

                       FROM pop, farm
                       WHERE pop.farm_id = farm.uid;

这是查看人口普查时间表的数据。人口普查中的每个人都将拥有基本的pop信息 - 姓氏,姓名,不动产的价值 - 但不是每个人都有农场。只有某些人在farm_id上的pop列中有一个值,对应于farm上该人的农场记录;否则farm_id为NULL。

但很自然地,上述查询只会获取那些pop.farm_id = farm.uid的人 - 也就是说,谁拥有农场,并拥有farm_id的值。无农场的个人被排除在外,我希望将其包含在farm中的相关all_households列的空值中。

现在,我知道我可以解决这个问题,到目前为止,每个链接列都有单独的SELECT语句,如下所示:

            CREATE TABLE all_households AS
                SELECT uid AS pop_uid,
                       surname,
                       given,
                       age,
                       real_property,

                       (SELECT uid FROM farm WHERE pop.farm_id = farm.uid) AS farm_uid,
                       (SELECT improved_acres FROM farm WHERE pop.farm_id = farm.uid) AS improved_acres,
                       (SELECT unimproved_acres FROM farm WHERE pop.farm_id = farm.uid) AS unimproved_acres,
                       (SELECT cash_value FROM farm WHERE pop.farm_id = farm.uid) AS cash_value,
                       (SELECT corn FROM farm WHERE pop.farm_id = farm.uid) AS corn,
                       (SELECT cotton FROM farm WHERE pop.farm_id = farm.uid) AS cotton

                       FROM pop;

但这看起来非常笨重而且不优雅。所以,我想知道是否有办法让上面的第一个查询从pop中选择条目,其中farm_id为NULL:

            WHERE pop.farm_id = farm.uid OR pop.farm_id IS NULL;

但事情变得非常混乱,我不确定为什么。在我真实的,未简化的查询中,我实际上处理的是四个表,每个表都有pop上的一列,可能是一个值,也可能是NULL,虽然上面的第一个查询只花了几秒钟,但查询这个WHERE挂了。永远。当我回来时,它已经因“数据库或磁盘已满”的错误而死亡。所以无论我做了什么,我似乎都引发了某种无限循环。我交替尝试了:

            WHERE (CASE WHEN pop.farm_id IS NOT NULL THEN pop.farm_id = farm.uid ELSE 1 END);

但这与以前的结果相同。谁能说清楚我做错了什么,或者我可能会做得更好?感谢。

1 个答案:

答案 0 :(得分:0)

您尝试使用farm_id IS NULL的速度很慢,因为数据库试图将每个 farm记录的组合与每个 {{1记录pop值。 此外,optimizing constraints with OR is not easy并使用临时表完成。

要获取所有匹配/已加入记录以及第一个表中没有相应服务器场的所有记录,请将两个查询与UNION ALL合并:

NULL

此构造称为outer join,并且在大多数SQL数据库中都是直接支持的(SQLite仅支持左连接,这是您想要的):

SELECT pop. ..., farm. ...
FROM pop JOIN farm ON pop.farm_id = farm.uid

UNION ALL

SELECT pop. ..., NULL, NULL, ...
FROM pop
WHERE pop.farm_id IS NULL

请注意,外部联接实际上会返回所有不匹配的记录,因此这也会返回SELECT pop. ..., farm. ... FROM pop LEFT OUTER JOIN farm ON pop.farm_id = farm.uid 个记录,其中pop无效。