【问题标题】:Translating subquery to left join in sqlite将子查询转换为sqlite中的左连接
【发布时间】:2015-01-14 17:01:48
【问题描述】:

我有一个针对使用几个子查询的 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 JOINs:

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 专家,我很难理解这里发生了什么。有没有一种直接的方法可以将子查询转换为联接?

【问题讨论】:

    标签: sql sqlite join


    【解决方案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 聚合函数中的条件表达式中做出的。

    【讨论】:

    • 谢谢 - 我什至没有意识到 CASE 表达式可以在 sum 中使用!
    猜你喜欢
    • 2012-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-12
    • 2021-08-08
    • 1970-01-01
    • 2016-03-02
    • 1970-01-01
    相关资源
    最近更新 更多