【问题标题】:SQL WHERE statements, where column may be value or may be NULLSQL WHERE 语句,其中列可能是值或可能是 NULL
【发布时间】:2013-08-09 22:22:22
【问题描述】:

我有一个 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 信息——姓氏、名字、不动产价值——但不是每个人都有农场。只有某些个人在popfarm_id 列中有值,对应于farm 上该人的农场记录;否则 farm_id 为 NULL。

但很自然,上述查询将只获取pop.farm_id = farm.uid 的个人——即拥有农场并拥有farm_id 的值的个人。没有农场的人被排除在外,我想将他们包括在内,all_households 中相关的farm 列的值为空。

现在,我知道我可以解决这个问题,并且到目前为止,为每个链接列使用单独的 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 (CASE WHEN pop.farm_id IS NOT NULL THEN pop.farm_id = farm.uid ELSE 1 END);

但这与以前的结果相同。任何人都可以阐明我做错了什么,或者我可以做得更好吗?谢谢。

【问题讨论】:

  • 我相信您正在寻找一个 OUTER JOIN,但我不知道如何按照您的 SQL 风格做到这一点。
  • 阅读连接类型。内、外、左、右...codinghorror.com/blog/2007/10/… 是一个很好的起点

标签: sql sqlite


【解决方案1】:

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

要获取所有匹配/连接的记录,以及第一个表中没有对应农场的所有记录,请将两个查询与UNION ALL 结合起来:

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

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

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

请注意,外连接实际上会返回所有不匹配记录,因此这也会返回带有无效farm_idpop 记录。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多