我在SQL Server中有一个包含以下数据的表:
+-----------------+-------------------+-------------------+--------+
|Product Family | Product Class | Product | Sales |
|Food | Vegetables | Cauliflower | 24 |
|Food | Prepared Meals | Steak & Patatoes | 54 |
|Food | Fruit | Apples | 76 |
|Food | Fruit | Oranges | 14 |
|Food | Fruit | Pears | 32 |
|Electronics | MP3 Players | Cool Player Z | 57 |
|Electronics | MP3 Players | iStuff 16GB | 45 |
|Electronics | TV's | HD | 96 |
|Electronics | TV's | Ultra HD | 76 |
+-----------------+-------------------+-------------------+--------+
此数据中有一个层次结构:
我想创建一个返回每个层次结构级别的总和的查询。这个联盟做到了:
SELECT 1 as Level, [Product Family] as Item, SUM(SALES) as Sales
FROM [dbo].[HK_Termp_01] GROUP BY [Product Family]
UNION ALL
SELECT 2 as Level, [Product Class] as Item, SUM(SALES) as Sales
FROM [dbo].[HK_Termp_01] GROUP BY [Product Class]
UNION ALL
SELECT 3 as Level, Product as Item, SUM(SALES) as Sales
FROM [dbo].[HK_Termp_01] GROUP BY Product
但是,我还需要一个额外的列,它将是层次结构顺序的3个字符串列的串联。所需的输出是:
+--------------------------+-----------------------------------------------+--------+
| Level ||Item | Hierarchy | Sales |
| 1 ||Electronics | Electronics | 274 |
| 1 ||Food | Food | 200 |
| 2 ||Fruit | Food > Fruit | 122 |
| 2 ||MP3 Players | Electronics > MP3 Players | 102 |
| 2 ||Prepared Meals | Food > Prepared Meals | 54 |
| 2 ||TV's | Electronics > TV's | 172 |
| 2 ||Vegetables | Food > Vegetables | 24 |
| 3 ||Apples | Food > Fruit > Apples | 76 |
| 3 ||Cauliflower | Food v Vegetables > Cauliflower | 24 |
| 3 ||Cool Player Z | Electronics > MP3 Players > Cool Player Z | 57 |
| 3 ||HD | Electronics > TV's > HD | 96 |
| 3 ||iStuff 16GB | Electronics v MP3 Players > iStuff 16GB | 45 |
| 3 ||Oranges | Food > Fruit > Oranges | 14 |
| 3 ||Pears | Food > Fruit v Pears | 32 |
| 3 ||Steak & Patatoes | Food v Prepared Meals > Steak & Patatoes | 54 |
| 3 ||Ultra HD | Electronics > TV's > Ultra HD | 76 |
+--------------------------+--------------+------+-------------------------+--------+
这是我被卡住的地方。我不能将所有3个字段添加到联盟中的每个查询,因为那样我没有按级别获得正确的总计。但我不确定尝试其他什么途径。
谢谢&让我知道我可以提供哪些其他信息来澄清案例。
答案 0 :(得分:3)
我认为您只想对您的查询进行调整:
SELECT 1 as Level, [Product Family] as Item,
SUM(SALES) as Sales
FROM [dbo].[HK_Termp_01]
GROUP BY [Product Family]
UNION ALL
SELECT 2 as Level, [Product Family] + '>' + [Product Class] as Item,
SUM(SALES) as Sales
FROM [dbo].[HK_Termp_01]
GROUP BY [Product Family] + '>' + [Product Class]
UNION ALL
SELECT 3 as Level, [Product Family] + '>' + [Product Class] + '>' + Product as Item,
SUM(SALES) as Sales
FROM [dbo].[HK_Termp_01]
GROUP BY [Product Family] + '>' + [Product Class] + '>' + Product;
那就是说,你可以使用GROUPING_SETS
:
SELECT [Product Family], [Product Class], Product, SUM(SALES) as Sales
FROM [dbo].[HK_Termp_01]
GROUP BY GROUPING SETS ( ([Product Family], [Product Class], Product),
([Product Family], [Product Class]),
([Product Family])
);
然后,您需要摆弄名称以获得所需的确切输出。
答案 1 :(得分:0)
只是为了好玩,
Declare @YourTable table ([Product Family] varchar(50),[Product Class] varchar(50),Product varchar(50),Sales int)
Insert Into @YourTable values
('Food','Vegetables','Cauliflower',24),
('Food','Prepared Meals','Steak & Patatoes',54),
('Food','Fruit','Apples',76),
('Food','Fruit','Oranges',14),
('Food','Fruit','Pears',32),
('Electronics','MP3 Players','Cool Player Z',57),
('Electronics','MP3 Players','iStuff 16GB',45),
('Electronics','TV''s','HD',96),
('Electronics','TV''s','Ultra HD',76)
Declare @Top varchar(25) = NULL --<< Sets top of Hier Try ''MP3 Players''
Declare @Nest varchar(25) = '|-----' --<< Optional: Added for readability
;with cte0 as (
Select Distinct ID=Product,Parent=[Product Class],Sales from @YourTable
Union All
Select Distinct ID=[Product Class],Parent=[Product Family],0 from @YourTable
Union All
Select Distinct ID=[Product Family],Parent='Total',0 from @YourTable
Union All
Select Distinct ID='Total',Parent=NULL,0 )
,cteP as (
Select Seq = cast(100000+Row_Number() over (Order by ID) as varchar(500))
,ID
,Parent
,Lvl=1
,Sales = Sales
From cte0
Where IsNull(@Top,'X') = case when @Top is null then isnull(Parent,'X') else ID end
Union All
Select Seq = cast(concat(p.Seq,'.',100000+Row_Number() over (Order by r.ID)) as varchar(500))
,r.ID
,r.Parent
,p.Lvl+1
,r.Sales
From cte0 r
Join cteP p on r.Parent = p.ID)
,cteR1 as (Select *,R1=Row_Number() over (Order By Seq) From cteP)
,cteR2 as (Select A.Seq,A.ID,R2=Max(B.R1) From cteR1 A Join cteR1 B on (B.Seq like A.Seq+'%') Group By A.Seq,A.ID )
Select A.R1
,B.R2
,A.ID
,A.Parent
,A.Lvl
,Title = Replicate(@Nest,A.Lvl-1) + A.ID
,Sales = (Select sum(Sales) from cteR1 S where S.R1 between A.R1 and B.R2)
From cteR1 A
Join cteR2 B on A.ID=B.ID
Group By A.R1,B.R2,A.ID,A.Parent,A.Lvl
Order By A.R1
返回
现在,如果你set @Top = 'MP3 Players'
而不是NULL,你会得到:
只是一点叙述:
cte0,我们将您的层次结构规范化为父/子关系
cteP,我们通过递归cte
构建您的层次结构cteR1,我们生成序列/ R1键
cteR2,我们生成R2密钥
现在,如果您有缓慢移动的层次结构,我倾向于使用范围键存储它们以便于导航和聚合。