【问题标题】:Need advice on whether PIVOT is the correct tool in SQL Server需要关于 PIVOT 是否是 SQL Server 中正确工具的建议
【发布时间】:2017-06-06 15:17:31
【问题描述】:

我的数据如下所示:

| ACCNT | AMOUNT | TYPE | YEAR |
|-------|--------|------|------|
|  458  | 168.80 | A    | 2014 |
|  458  | 282.77 | A    | 2015 |
|  458  | 64.70  | B    | 2015 |
|  458  | 91.25  | A    | 2016 |
|  458  | 398.00 | B    | 2016 |
|  458  | 104.45 | C    | 2016 |
|  927  | 445.00 | B    | 2014 |
|  927  | 25.00  | A    | 2015 |
|  927  | 10.00  | NULL | 2015 |
|  927  | 132.00 | A    | 2016 |
|  927  | 381.40 | B    | 2016 |
|  927  | 210.00 | C    | 2016 |
...

Accnt 可能没有每个 Year 的值,并且 Type 偶尔会为 NULL。 我希望每个账户只有一行,并结合年份标题下的金额和类型列,即让它看起来像这样:

| ACCNT |   2014    |       2015         |           2016             |
|-------|-----------|--------------------|----------------------------|
|  458  | 168.80,A  | 282.77,A;64.70,B   | 91.25,A;398.00,B;104.45,C  |  
|  927  | 445.00,B  | 25.00,A;10.00,NULL | 132.00,A;381.40,B;210.00,C |
...

我可以在 [年] 上旋转...

SELECT * FROM 
 (SELECT [Accnt], [Amount], [Type], [Year] FROM data_table) 
 AS Source
PIVOT
(
 MAX([Amount]) FOR [Year] IN ([2014],[2015],[2016])
) AS PVT

...但每个帐户仍然有多个行。

以下更接近我正在寻找的格式...

SELECT Accnt, [1] AS '2014', [2] AS '2015', [3] AS '2016'
FROM (SELECT ROW_NUMBER() OVER (PARTITION BY Accnt ORDER BY [Year] Asc) AS AccountID, 
Accnt, CONVERT(nvarchar,Amount) + ',' + [Type]  AS Amount_And_Type
FROM  data_table) PIVOT (MAX(Amount_And_Type) 
FOR AccountID IN ([1], [2], [3])) AS data_pvt

...但它只是给了我每个 Accnt 的前三行:

| ACCNT |   2014    |   2015   |  2016   |
|-------|-----------|----------|---------|
|  458  | 168.80,A  | 282.77,A | 67.40,B |  
|  927  | 445.00,B  | 25.00,A  | NULL    |

我正在尝试使用 Pivot 来实现吗?

【问题讨论】:

  • 理想情况下,数据的表示将在表示层处理;不在数据层。那就是说为什么数据库有一个支点呢?
  • 看看stufffor xml 用于将数据行转换为单个字段的函数。

标签: sql-server sql-server-2008-r2 pivot row-number


【解决方案1】:

您可以如下查询:

;with cte as (
    select Accnt, iif([2014] is null,null, concat([2014],',',[Type])) as [2014a]
        ,iif([2015] is null,null, concat([2015],',',[Type])) as [2015a]
        ,iif([2016] is null,null, concat([2016],',',[Type])) as [2016a]
     from youracct
    pivot(max(amount) for [year] in ([2014],[2015],[2016])) p
) 
select c.Accnt, [2014]= stuff(( Select ';'+[2014a] from cte where Accnt = c.Accnt for xml path('')),1,1,'')    
,[2015]=stuff(( Select ';'+[2015a] from cte where Accnt = c.Accnt for xml path('')),1,1,'')  
,[2016]=stuff(( Select ';'+[2016a] from cte where Accnt = c.Accnt for xml path('')),1,1,'')  
from cte c
group by c.Accnt

但这种方法的动态 sql 有点复杂,但我们可以做到..

输出如下:

+-------+---------+-----------------+------------------------+
| Accnt |  2014   |      2015       |          2016          |
+-------+---------+-----------------+------------------------+
|   458 | 168.8,A | 282.77,A;64.7,B | 91.25,A;398,B;104.45,C |
|   927 | 445,B   | 10,;25,A        | 132,A;381.4,B;210,C    |
+-------+---------+-----------------+------------------------+

【讨论】:

  • iifconcat 在 SQL Server 2008 R2 中不起作用,所以我尝试了以下方法:选择 Accnt, case [2014] when NULL then 'NULL' else (CONVERT(nvarchar,[2014]) + ',' + [Type]) end as [2014a],... 但它忽略了 NULL 类型的 10.00 数量。我对这个查询的工作原理的理解不够深入,无法弄清楚为什么会发生这种情况。
  • for iif 你可以使用 coalesce 而不是 concat 你可以使用 +
  • 让我尝试解释一下...如果您单独查询 CTE,它将获得枢轴年份,并且用于连接的东西
  • 尝试通过在 CTE 下面添加 select * from CTE 来单独运行 CTE,您将获得输入
猜你喜欢
  • 2019-01-31
  • 1970-01-01
  • 2016-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多