连接来自不同T-SQL查询的值

时间:2017-01-10 18:34:22

标签: sql-server tsql

我在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     |
+-----------------+-------------------+-------------------+--------+

此数据中有一个层次结构:

  1. 产品系列
  2. 产品类别
  3. 产品
  4. 我想创建一个返回每个层次结构级别的总和的查询。这个联盟做到了:

    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个字段添加到联盟中的每个查询,因为那样我没有按级别获得正确的总计。但我不确定尝试其他什么途径。

    谢谢&让我知道我可以提供哪些其他信息来澄清案例。

2 个答案:

答案 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

返回

enter image description here

现在,如果你set @Top = 'MP3 Players'而不是NULL,你会得到:

enter image description here

只是一点叙述:

cte0,我们将您的层次结构规范化为父/子关系

cteP,我们通过递归cte

构建您的层次结构

cteR1,我们生成序列/ R1键

cteR2,我们生成R2密钥

现在,如果您有缓慢移动的层次结构,我倾向于使用范围键存储它们以便于导航和聚合。