【问题标题】:transpose rows to columns in sql将行转置为sql中的列
【发布时间】:2014-05-06 04:06:22
【问题描述】:

我无法通过 SQL 查询获得所需的输出。

我的sql数据如下:

TOTAL   Charge      PAYMNET      A         B        C          D       E      MonthYear
------- ----------- ----------- --------- -------- ---------- ------- ------- ----------
661     157832.24   82967.80    700.00    10.70    58329.33   0.00    0.00    Oct-2013
612     95030.52    17824.28    850.00    66.10    53971.41   0.00    0.00    Nov-2013
584     90256.35    16732.91    700.00    66.10    52219.87   0.00    0.00    Dec-2013
511     72217.32    12336.12    285.00    53.17    42951.12   0.00    0.00    Jan-2014

我需要输出如下,

Data            Jan-2013            Feb-2013            Mar-2013

TOTALCOUNT      761                 647                 671
Charge          126888              119995              151737.5
Payment         25705.4             26235.47            28704.41
A               1089.08             1020                745
B               2100.4              1947.25             1868.22
C               94246.55            84202.15            115673.7
D               0                   0                   0
E               0                   0                   0

我已经看到pivotunpivot 的示例,在pivot 我没有将列标题作为行数据,在unpivot 我没有找到可以转置多个的示例列。我有另一个选择可以在代码中得到这个结果。但是我想知道在sql中是否可以得到这种结果?

编辑

结果只会给出3或4个月,不会超过那个。

更新:第一个示例数据是我将通过多个连接和对多个表进行分组而获得的实际数据,我将其存储到临时表中。我试图通过修改由于表结构而不可能的查询来获得所需的结果。我设法得到了第一个示例数据中的结果,但这不是客户想要看到的!!!所以我需要将只有 3 到 4 行的临时表数据处理成所需的输出。获得第一个结果的查询是select * from temp。需要对temp表结果进行处理。

Update-2

我尝试了以下查询

declare @cols varchar(max)
select @cols = STUFF((select ', ' + MonthYear
                      from #tmp for xml path('')),1,1,'')

declare @query varchar(max)
set @query = 
        'select ''TOTAL'' as Data,' +@cols+' from
        (select MonthYear,TOTALCLAIMS from #tmp)st
        pivot
        (
            MAX(TOTAL) for MonthYear in (' + @cols + ')
        )pt;'

这给了我正确的第一行!!!但我尝试使用union as

set @query = 
        'select ''TOTAL'' as Data,' +@cols+' from
        (select MonthYear,TOTALCLAIMS from #tmp)st
        pivot
        (
            MAX(TOTAL) for MonthYear in (' + @cols + ')
        )pt;
        union
        select ''CHARGES'' as Data,' +@cols+' from
        (select MonthYear,TOTALCLAIMS from #tmp)st
        pivot
        (
            MAX(CHARGES) for MonthYear in (' + @cols + ')
        )pt;'

这给出了incorrect syntax near union 的错误。有人知道如何合并pivot 结果吗?或者有没有更好的方法来做到这一点?

谢谢。

【问题讨论】:

  • 同一个monthyear会有多条记录吗?如果是,那么应该如何处理它们?请说明。
  • @samar 不。我不会在同一年和同一年有多个记录。
  • 这可能会有所帮助,但它不是微不足道的stackoverflow.com/questions/18023479/…
  • 另一种方法是循环遍历表并创建所需的表。但这并不容易,无论是在编码方面还是在性能方面。
  • 去掉每个并集前的分号

标签: sql sql-server sql-server-2008 unpivot


【解决方案1】:

我已经尝试过这段代码。请检查并告诉我它是否有效

我知道它看起来不太好。也不确定性能如何。

--Can have more columns like A,B,...
DECLARE @tbl TABLE
(
TOTAL INT,
CHARGE FLOAT,
PAYMENT FLOAT,
MONTHYEAR VARCHAR(50)
)


--Test data
INSERT INTO @tbl SELECT 661, 157832.24, 82967.80, 'Oct2013'
INSERT INTO @tbl SELECT 612,     95030.52,    17824.28, 'Nov2013'
INSERT INTO @tbl SELECT 584     ,90256.35,    16732.91, 'Dec2013'

--Can be a physical table
CREATE TABLE #FinalTbl 
(
DATA VARCHAR(100)
)

--inserted hardcode records in data column. To add it dynamically you would need to loop through information_schema.columns
--SELECT *
--FROM information_schema.columns
--WHERE table_name = 'tbl_name'
INSERT INTO #FinalTbl
VALUES ('TOTAL')

INSERT INTO #FinalTbl
VALUES ('CHARGE')

INSERT INTO #FinalTbl
VALUES ('PAYMENT')

DECLARE @StartCount INT, @TotalCount INT, @Query VARCHAR(5000), @TOTAL INT,@CHARGE FLOAT,@PAYMENT FLOAT,@MONTHYEAR VARCHAR(50)

SELECT @TotalCount = COUNT(*) FROM @tbl;
SET @StartCount = 1;

WHILE(@StartCount <= @TotalCount)
BEGIN
    SELECT @TOTAL = TOTAL, 
    @CHARGE = CHARGE,
    @PAYMENT = PAYMENT,
    @MONTHYEAR = MONTHYEAR  
    FROM
    (SELECT ROW_NUMBER() over(ORDER BY MONTHYEAR) AS ROWNUM, * FROM @tbl) as tbl
    WHERE ROWNUM = @StartCount

    SELECT @Query = 'ALTER TABLE #FinalTbl ADD ' + @MONTHYEAR + ' VARCHAR(1000)'
    EXEC (@Query)

    SELECT @Query = 'UPDATE #FinalTbl SET ' + @MONTHYEAR + ' = ''' + CONVERT(VARCHAR(50), @TOTAL) + ''' WHERE DATA = ''TOTAL'''
    EXEC (@Query)

    SELECT @Query = 'UPDATE #FinalTbl SET ' + @MONTHYEAR + ' = ''' + CONVERT(VARCHAR(50), @CHARGE) + ''' WHERE DATA = ''CHARGE'''
    EXEC (@Query)

    SELECT @Query = 'UPDATE #FinalTbl SET ' + @MONTHYEAR + ' = ''' + CONVERT(VARCHAR(50), @PAYMENT) + ''' WHERE DATA = ''PAYMENT'''
    EXEC (@Query)

    SELECT @StartCount = @StartCount + 1
END

SELECT * FROM #FinalTbl

DROP TABLE #FinalTbl

希望对你有帮助

【讨论】:

  • 此查询单独运行良好。但是当我在我的过程中实现相同的操作时,它会在除data 列之外的所有列中显示null 值。
  • 知道了 :) 列名不匹配。谢谢。
【解决方案2】:

我想你只得到 3 或 4 个月的原因是因为你没有缺失月份的数据?如果您想显示缺失月份的列,您需要:

  1. 创建一个表数据类型,其中包含要显示的所有月份 并在您的查询中将其余表连接到它。你 然后可以正常使用 PIVOT 功能。

  2. 如果您知道有多少列,即特定年份的每个月有多少列并且它不会改变,您可以简单地使用 CASE 用于转置数据的语句(每个月一个) PIVOT 运算符。

如果需要,我可以提供示例。

【讨论】:

  • 没有缺失月份。仅重新发送 3 或 4 个月的数据。我在问题中显示的是示例数据。
  • 请显示您的查询以提供帮助
  • 我给出的结果就是我进入临时表的结果。我无法更改主查询[我不允许 :(] 及其太大的查询。
【解决方案3】:
Select Month(Mdate)md,'A' AS Col,sum(A) as a from Product group by Month(MDate)
union all
Select Month(Mdate)md,'B',sum(b) as a from Product group by Month(MDate)
union all
Select Month(Mdate)md,'C',sum(c) as a from Product group by Month(MDate)
union all
Select Month(Mdate)md,'D',Count(A) as a from Product group by Month(MDate)

使用上述查询尝试Pivot,您可能会得到所需的结果....

【讨论】:

  • 以上查询为select * from tmp。您能否将pivot 查询也作为结果发布。
猜你喜欢
  • 2019-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-15
  • 2013-12-05
相关资源
最近更新 更多