按多个表中的值分组的聚合[SQL]

时间:2016-08-01 23:49:30

标签: sql sql-server ssms sql-server-2014 ssms-2014

我有两个表#Test#Control,它们彼此具有相同的列,如下所示:

#Test:                        #Control:
Name  Component  Price        Name  Component  Price
A     a          1.00         A     a          7.00
A     b          2.00         A     a          8.00
A     a          3.00         B     a          9.00
B     a          4.00         B     d          10.00
B     a          5.00         B     d          11.00
B     c          6.00     

但有NameComponent的更多列和组合。

我想将它们聚合在一起以得到PriceNameComponent的总和,但是我想要一个列表中出现的所有组合的值。使用上面的示例表所需的输出如下所示:

#TestAgg:                        #ControlAgg:
Name  Component  SumPrice        Name  Component  SumPrice
A     a          4.00            A     a          15.00
A     b          2.00            A     b          0.00
B     a          9.00            B     a          9.00
B     c          6.00            B     c          0.00
B     d          0.00            B     d          21.00

我该怎么做?

对于单个表,以下工作:

SELECT Name
       ,Component
       ,sum(Price) as SumPrice                  
INTO #TestAgg
FROM #Test
GROUP BY rollup(Name,Component)
order by 1, SumPrice desc 

但是我无法弄清楚如何为只存在于另一个表中的Name-Component组合返回零。

1 个答案:

答案 0 :(得分:1)

你可以试试这个:

CREATE TABlE #Test(Name VARCHAR(1), Component VARCHAR(1),  Price DECIMAL(14,4));
INSERT INTO #Test VALUES
 ('A','a',1.00)    
,('A','b',2.00)    
,('A','a',3.00)   
,('B','a',4.00)    
,('B','a',5.00)    
,('B','c',6.00);     

CREATE TABlE #Control(Name VARCHAR(1), Component VARCHAR(1),  Price DECIMAL(14,4));
INSERT INTO #Control VALUES
 ('A','a',7.00)
,('A','a',8.00)
,('B','a',9.00)
,('B','d',10.00)
,('B','d',11.00);

- 首先,我使用CTE获取两个表的所有组合的明确列表

WITH AllCombos AS
(
    SELECT DISTINCT Name,Component
    FROM #Test
    UNION --without "ALL" it will be distinct over the tables
    SELECT DISTINCT Name,Component
    FROM #Control
)

- 现在我使用LEFT JOIN来获取两个结果集 - 并使用最终GROUP BY

SELECT Source,Name,Component,ISNULL(SUM(Price),0) AS Price
FROM
(
    SELECT 'Test' AS Source, AC.Name,AC.Component,T.Price
    FROM AllCombos AS AC
    LEFT JOIN #Test AS T ON AC.Component=T.Component AND AC.Name=T.Name
    UNION ALL
    SELECT 'Control',AC.Name,AC.Component,C.Price
    FROM AllCombos AS AC
    LEFT JOIN #Control AS C ON AC.Component=C.Component AND AC.Name=C.Name
) AS tbl
GROUP BY Source,Name,Component

--Clean-up
GO
DROP TABLE #Test;
DROP TABLE #Control;

结果

Control A   a   15.0000
Control A   b   0.0000
Control B   a   9.0000
Control B   c   0.0000
Control B   d   21.0000
Test    A   a   4.0000
Test    A   b   2.0000
Test    B   a   9.0000
Test    B   c   6.0000
Test    B   d   0.0000

更新

如果你真的需要两张桌子,你可以写

SELECT ... INTO #ControlAgg 
FROM (...) AS tbl 
WHERE Source='Control' 
GROUP BY ...

(与测试相同)

...并且两次调用......或者 - 在我看来更好 - 你在一个commong表中写这个并在查询中使用Source来将它们分开......