在SQL Server中透视多行

时间:2014-08-22 07:49:18

标签: sql sql-server sql-server-2008 tsql pivot

我有以下数据:

CREATE TABLE #Temp
(RuleName VARCHAR(100),
ParamValue VARCHAR(100),
ParamName VARCHAR(100))

INSERT INTO #Temp
VALUES ('BroadBandAviva','BroadBandAviva1','Rule Name'),
('BroadBandAviva','BroadBand','Expense Category name'),
('BroadBandAviva','DSF','org unit name'),
('BroadBandAviva','ASSISTANT SALES MANAGER','designation'),
('BroadBandAviva','Category   A','cityclassification'),
('BroadBandAviva','2000','Eligible Amount'),
('BroadBandAviva','BroadBandAviva2','Rule Name'),
('BroadBandAviva','BroadBand','Expense Category name'),
('BroadBandAviva','DSF','org unit name'),
('BroadBandAviva','ASSISTANT SALES MANAGER','designation'),
('BroadBandAviva','ROI-Rest   of India','cityclassification'),
('BroadBandAviva','2000','Eligible Amount')

我希望输出如下:

RuleName    Col1    Col2    Col3    Col4    Col5    Col6
---------------------------------------------------------------------------------
BroadBandAviva  Rule Name   Expense Category name   org unit name   designation cityclassification  Eligible Amount
BroadBandAviva  BroadBandAviva1 BroadBand   DSF ASSISTANT SALES MANAGER Category   A    2000
BroadBandAviva  BroadBandAviva2 BroadBand   DSF ASSISTANT SALES MANAGER ROI-Rest   of India 2000

基本上第一列应该保持不变,第三列应该成为第一行,第二列应该从第二列开始。我尝试使用枢轴功能,但我无法获得所需的输出。

2 个答案:

答案 0 :(得分:1)

这是我能得到的,也许其他人可以使用它?请注意,下面的2000位置错误,我看不出原因或方法。

|       RULENAME |  PARAMS                                                                                            |
|----------------|----------------------------------------------------------------------------------------------------|
| BroadBandAviva |  Rule Name, Expense Category name, org unit name, designation, cityclassification, Eligible Amount |
| BroadBandAviva |        BroadBandAviva1, BroadBand, DSF, ASSISTANT SALES MANAGER, Category   A                      |
| BroadBandAviva |  2000, BroadBandAviva2, BroadBand, DSF, ASSISTANT SALES MANAGER, ROI-Rest   of India               |
                    ^^^^^

这是我使用的查询:

declare @i int = (select count(distinct ParamName) from Temp)

;with cte as (
select 
        *
      , row_number() over(order by (select 1)) as rn
      , row_number() over(order by (select 1)) / @i as grpno
      , row_number() over(order by (select 1)) % @i as prow
from temp
)

SELECT
        (select RuleName from cte where rn = 1) as RULENAME
      , STUFF((
              SELECT
                    ', ' + c2.ParamName
              FROM CTE as c2
              WHERE rn <= @i
              order by c2.rn
              FOR XML PATH ('')
              )
             , 1, 1, '') as PARAMS
         --, -1, -1, -1

UNION ALL

select
      cte.RuleName
    , caxml.params
       --, cte.grpno, prow, rn
from cte
CROSS APPLY (
          SELECT
              STUFF((
                    SELECT
                          ', ' + c2.ParamValue
                    FROM CTE as c2
                    WHERE c2.grpno = cte.grpno
                    order by case when c2.prow = @i then @i else c2.prow end
                    FOR XML PATH ('')
                    )
                   , 1, 1, '')
         ) caxml (params)
where prow = 1
;

see SQLFiddle Demo for more

答案 1 :(得分:1)

这是一种替代方法,它将值放在单独的列中,如下所示:

|       RULENAME | GRPNO |            COL1 |                  COL2 |          COL3 |                    COL4 |                COL5 |            COL6 |
|----------------|-------|-----------------|-----------------------|---------------|-------------------------|---------------------|-----------------|
| BroadBandAviva |    -1 |       Rule Name | Expense Category name | org unit name |             designation |  cityclassification | Eligible Amount |
| BroadBandAviva |     0 | BroadBandAviva1 |             BroadBand |           DSF | ASSISTANT SALES MANAGER |        Category   A |            2000 |
| BroadBandAviva |     1 | BroadBandAviva2 |             BroadBand |           DSF | ASSISTANT SALES MANAGER | ROI-Rest   of India |            2000 |

与我之前的尝试一样,我使用CTE来保留一些在后续联合中重复使用的必要计算。与之前的尝试不同,我使用传统的case expressionsgroup by来实现支点。这是查询。

declare @i int = (select count(distinct ParamName) from Temp)

;with cte as (
select 
        *
      , row_number() over(order by (select 1)) as rn
      , (row_number() over(order by (select 1))-1) / @i as grpno
      , row_number() over(order by (select 1)) % @i as prow
from temp
)
select
        rulename
      , -1 as grpno
      , max(case when prow = 1 then paramname end) as col1
      , max(case when prow = 2 then paramname end) as col2
      , max(case when prow = 3 then paramname end) as col3
      , max(case when prow = 4 then paramname end) as col4
      , max(case when prow = 5 then paramname end) as col5
      , max(case when prow = 0 then paramname end) as col6
from cte
WHERE rn <= @i
group by
        rulename

union all

select
        rulename
      , grpno
      , max(case when prow = 1 then paramvalue end) as col1
      , max(case when prow = 2 then paramvalue end) as col2
      , max(case when prow = 3 then paramvalue end) as col3
      , max(case when prow = 4 then paramvalue end) as col4
      , max(case when prow = 5 then paramvalue end) as col5
      , max(case when prow = 0 then paramvalue end) as col6
from cte
group by
        rulename
      , grpno

;

要遵循逻辑,了解列PROW(参数行)和GRPNO(分组编号)非常有用,以下是显示这些列的CTE内容:

/*
|       RULENAME |              PARAMVALUE |             PARAMNAME | RN | GRPNO | PROW |
|----------------|-------------------------|-----------------------|----|-------|------|
| BroadBandAviva |         BroadBandAviva1 |             Rule Name |  1 |     0 |    1 |
| BroadBandAviva |               BroadBand | Expense Category name |  2 |     0 |    2 |
| BroadBandAviva |                     DSF |         org unit name |  3 |     0 |    3 |
| BroadBandAviva | ASSISTANT SALES MANAGER |           designation |  4 |     0 |    4 |
| BroadBandAviva |            Category   A |    cityclassification |  5 |     0 |    5 |
| BroadBandAviva |                    2000 |       Eligible Amount |  6 |     0 |    0 |
| BroadBandAviva |         BroadBandAviva2 |             Rule Name |  7 |     1 |    1 |
| BroadBandAviva |               BroadBand | Expense Category name |  8 |     1 |    2 |
| BroadBandAviva |                     DSF |         org unit name |  9 |     1 |    3 |
| BroadBandAviva | ASSISTANT SALES MANAGER |           designation | 10 |     1 |    4 |
| BroadBandAviva |     ROI-Rest   of India |    cityclassification | 11 |     1 |    5 |
| BroadBandAviva |                    2000 |       Eligible Amount | 12 |     1 |    0 |
*/

see the SQLFiddle Demo