为什么子查询中的聚合必须再次聚合?

时间:2013-12-17 19:27:06

标签: sql sql-server subquery aggregates

我希望我在下面正确地将查询放在一起。我从一些更大,更大的东西中简化了。但是我的问题应该从示例中清楚地说明。

在最里面的查询nest1中,假设结果返回发票123的三个条目。发票创建(1),然后两个现金存款(2,3),第二个其中(3)付清了发票。从那个结果集中,我汇总了总和。我也得到了paid_off_date,其中只有一行会有。

我很高兴能够学习更好的方法来设计这个查询,但我不明白为什么我必须一直选择聚合。例如,当我在SUM(cash_deposit) AS 'cash_deposit'中选择nest2时,为什么还必须在最外层的查询中选择SUM(cash_deposit)?一旦在子查询中聚合,为什么聚合不会传递?为什么我必须在每个级别按ID分组?

SELECT id, SUM(cash_deposit), MAX(paid_off_date), MAX(job_phase), MAX(cust_id)
FROM
(
    SELECT id AS id, SUM(cash_deposit) AS 'cash_deposit', MAX(paid_off_date) AS 'paid_off_date', MAX(job_phase) AS 'job_phase'
    FROM
    (
         SELECT id, cash_deposit, paid_off_date
         FROM invoice
         GROUP BY id
    ) nest1
    JOIN    job j
            ON nest1.id = j.id
    GROUP BY id
) nest2
JOIN    customer c
        ON c.invoice = nest2.id
GROUP BY id

澄清

感谢任何有改进版本查询的帖子。我正在使用现有的查询,当我开始尝试将嵌套转换为连接时,会产生意外的结果。我将继续玩它,但我也非常感谢有人可以回答有关聚合的问题以及为什么在嵌套时必须重复这些问题。在C#中,我可以在一个函数中总结三个数字,然后将结果值传回。我不必总结结果。我需要一些帮助来理解SQL子查询在这方面的功能如何。

可能的答案

我的一位同事指出,在这种情况下,这是因为我的GROUP BY条款。例如,由于cash_depositjob_phase不在GROUP BY子句中,因此必须对它们进行汇总。

3 个答案:

答案 0 :(得分:1)

SELECT i.id, SUM(i.cash_deposit), MAX(i.paid_off_date), MAX(j.job_phase), MAX(c.cust_id)
FROM invoice i
JOIN job j ON j.id = i.id
JOIN customer c ON c.invoice = i.id
GROUP BY id

答案 1 :(得分:1)

它强制您重新运行聚合,因为您在查询的每个步骤中都放置了group by。如果从除最内层查询之外的所有查询中删除group by id,则无需重新进行聚合。

尝试这样写:

SELECT id, cash_deposit, paid_off_date, job_phase, cust_id
FROM
(
    SELECT id AS id, SUM(cash_deposit) AS 'cash_deposit', MAX(paid_off_date) AS 'paid_off_date', job_phase
    FROM
    (
         SELECT id, cash_deposit, paid_off_date
         FROM invoice
         GROUP BY id
    ) nest1
    JOIN    job j
            ON nest1.id = j.id
) nest2
JOIN    customer c
        ON c.invoice = nest2.id

您现在也可以使用相同的结果集一步完成两个连接,但我想向您展示必要的最小更改量。

答案 2 :(得分:0)

select id, 
    sum(cash_deposit) as [cash_deposit],
    max(paid_off_date) as [paid_off_date],
    jp.[job_phase],
    cid.[cust_id]
from invoice i
cross apply (
    select max(job_phase) as [job_phase]
    from job j
    where j.id = i.id) jp
cross apply (
    select max(cust_id) as [cust_id]
    from customer c
    where i.id = c.invoice) cid