将子查询转换为sqlite中的左连接

时间:2015-01-14 17:01:48

标签: sql sqlite join

我有一个针对使用几个子查询的SQLite数据库运行的查询。为了适应一些新的要求,我需要将其翻译为使用连接。以下是原始查询的结构版本:

SELECT c.id AS category_id, b.budget_year,
(
    SELECT sum(actual)
    FROM lines l1
    WHERE status = 'complete'
    AND category_id = c.id
    AND billing_year = b.budget_year
) AS actual
(
    SELECT sum(planned)
    FROM lines l2
    WHERE status IN ('forecasted', 'in-progress')
    AND category_id = c.id
    AND billing_year = b.budget_year
) AS rough_proposed
FROM categories AS c
LEFT OUTER JOIN budgets AS b ON (c.id = b.category_id)
GROUP BY c.id, b.budget_year;

下一个查询是我第一次尝试将其转换为使用LEFT OUTER JOIN s:

SELECT c.id AS category_id, b.budget_year, sum(l1.actual) AS actual, sum(l2.planned) AS planned
FROM categories AS c
LEFT OUTER JOIN budgets AS b ON (c.id = b.category_id)
LEFT OUTER JOIN lines AS l1 ON (l1.category_id = c.id
    AND l1.billing_year = b.budget_year
    AND l1.status = 'complete')
LEFT OUTER JOIN lines AS l2 ON (l2.category_id = c.id
    AND l2.billing_year = b.budget_year
    AND l2.status IN ('forecasted', 'in-progress'))
GROUP BY c.id, b.budget_year;

但是,actualrough_proposed大于预期。我不是SQL专家,我很难理解这里发生了什么。有没有一种直接的方法将子查询转换为连接?

1 个答案:

答案 0 :(得分:1)

您的查询都存在问题。但是,第一个查询会隐藏问题,而第二个查询会使问题可见。

以下是正在发生的事情:您加入lines两次 - 一次为l1,另一次为l2。当存在实际行和预测/正在进行的行时,分组前的查询将多次具有相同的行。发生这种情况时,每一行都会被计算多次,导致价值膨胀。

第一个查询会隐藏此内容,因为它不会将聚合应用于actualrough_proposed列。 SQLite为每个组选择第一个条目,该条目具有正确的值。

您可以通过仅连接一次行来修改查询,并有条件地计算金额,如下所示:

SELECT
    c.id AS category_id
,   b.budget_year
,   SUM(CASE WHEN l.status = 'complete' THEN l.actual END) AS actual
,   SUM(CASE WHEN l.status IN ('forecasted', 'in-progress') THEN l.planned END) AS planned
FROM categories AS c
LEFT OUTER JOIN budgets AS b ON (c.id = b.category_id)
LEFT OUTER JOIN lines AS l ON (l.category_id = c.id AND l1.billing_year = b.budget_year)
GROUP BY c.id, b.budget_year

在这个新查询中,lines的每一行只会被带入一次;在actual / planned列之一中对其进行计数的决定是在SUM聚合函数中嵌入的条件表达式中进行的。