1

我有一个 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;

但这似乎非常笨拙和不雅。所以,我想知道是否有办法让上面的第一个查询从NULLpop中获取条目:farm_id

            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);

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

4

1 回答 1

0

您尝试使用farm_id IS NULL的速度很慢,因为数据库试图为您提供每条 farm记录与每条 pop记录的组合NULL值。此外,使用 OR 优化约束并不容易,而是使用临时表完成的。

要获取所有匹配/连接的记录,以及第一个表中没有相应场的所有记录,请将两个查询与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

这种结构称为外连接,大多数 SQL 数据库都直接支持(SQLite 仅支持左连接,这正是您想要的):

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

请注意,外连接实际上会返回所有不匹配的记录,因此这也会返回pop带有 invalid 的记录farm_id

于 2013-08-10T07:22:29.673 回答