帮助Pivot / Unpivot

时间:2010-03-05 00:34:24

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

我有一张表格如下

Name    Priority    Date    
-------------------------
A         2          d1
B         3          d2

如何编写查询以实现以下输出

ColumnNames   d1      d2
--------------------------
 Name         A       B
 Priority     2       3

由于

3 个答案:

答案 0 :(得分:3)

这是我承诺的解决方案:

编辑:我修改了答案以回答OP的其他问题。

有几点需要注意:

  • STUFF函数:用于将XML字符串转换为常规字符串(并删除第一个逗号)
  • Group By(我从OMG小马那里偷了这个):你需要这样做以确保你没有任何重复日期
  • 确保在运行此表之前表中没有太多日期。太多列可能是个问题
  • NVARCHAR:我使用此代替VARCHAR作为@sql变量,因为sp_ExecuteSQL需要它。
  • CONVERT(VARCHAR,DateColumn,101):我这样做是因为除非你将日期转换为字符串,否则这不会起作用。 101结果:mm / dd / yyyy但你可以使用你需要的任何东西(确保它在这个剧本中使用2次匹配)
  • 为了使其适用于多个列,您必须首先使用UNPIVOT并将所有列转换为相同的数据类型(代码下方的更多信息)
  • 重要的是要注意,为了连接字符串,它们必须具有相同的数据类型,具有相同的大小(在我的情况下,它们都是NVARCHAR(MAX))

有关将日期转换为字符串的详细信息,请阅读this page

话虽如此,这是代码:

-- table with multiple columns
CREATE TABLE #TBL ( 
    NameColumn VARCHAR(10), 
    PriorityColumn INT,
    AnotherColumn FLOAT,
    DateColumn DATETIME 
)


-- Insert the test data
INSERT INTO #TBL VALUES ('a', 1, 7.2, '1/1/2000')
INSERT INTO #TBL VALUES ('a', 2, 8.9, '1/2/2000')
INSERT INTO #TBL VALUES ('a', 2, 53.2, '1/3/2000')
INSERT INTO #TBL VALUES ('a', 3, 9.12, '1/4/2000')
INSERT INTO #TBL VALUES ('b', 2, 1.26, '1/1/2001')


DECLARE
    @sql NVARCHAR(max),
    @dates NVARCHAR(max)


-- I separated this to make the code easier to read
SET @dates = STUFF(
    (
        SELECT N',[' + CONVERT(VARCHAR, DateColumn, 101) + ']' AS [text()]
        FROM #TBL
        GROUP BY DateColumn
        ORDER BY DateColumn
        FOR XML PATH('')
    ), 1, 1, N''
)


-- I will break this part of the code up below
SET @sql = N'SELECT
    *
FROM (
    SELECT
        ColumnName,
        ColumnValue,
        CONVERT(VARCHAR, DateColumn, 101) AS DateString
    FROM (
        SELECT
            CAST(NameColumn AS VARCHAR(100)) AS NameColumn,
            CAST(PriorityColumn AS VARCHAR(100)) AS PriorityColumn,
            CAST(AnotherColumn AS VARCHAR(100)) AS AnotherColumn,
            DateColumn
        FROM #TBL
    ) P
    UNPIVOT (
        ColumnValue
        FOR ColumnName IN (NameColumn, PriorityColumn, AnotherColumn)
    ) UNPIV
) P2
PIVOT (
    MAX(ColumnValue)
    FOR DateString IN (' + @dates + N')
) PIV'

EXECUTE dbo.sp_ExecuteSQL @sql


DROP TABLE #TBL

让我们来看看这个

-- I first do an UNPIVOT on all of the columns I want to pivot on, at the same time, converting them to the same datatype
SELECT
    ColumnName,
    ColumnValue,
    CONVERT(VARCHAR, DateColumn, 101) AS DateString
FROM (
    SELECT
        CAST(NameColumn AS VARCHAR(100)) AS NameColumn,
        CAST(PriorityColumn AS VARCHAR(100)) AS PriorityColumn,
        CAST(AnotherColumn AS VARCHAR(100)) AS AnotherColumn,
        DateColumn
    FROM #TBL
) P
UNPIVOT (
    ColumnValue
    FOR ColumnName IN (NameColumn, PriorityColumn, AnotherColumn)
) UNPIV

一旦我这样做,数据将如下所示:

ColumnName  ColumnValue DateString
----------------------------------
NameColumn      a       01/01/2000
PriorityColumn  1       01/01/2000
AnotherColumn   7.2     01/01/2000
NameColumn      a       01/02/2000
PriorityColumn  2       01/02/2000
AnotherColumn   8.9     01/02/2000
NameColumn      a       01/03/2000
PriorityColumn  2       01/03/2000
AnotherColumn   53.2     01/03/2000
NameColumn      a       01/04/2000
PriorityColumn  3       01/04/2000
AnotherColumn   9.12     01/04/2000
NameColumn      b       01/01/2001
PriorityColumn  2       01/01/2001
AnotherColumn   1.26     01/01/2001

然后我们可以像这样使用PIVOT来获取我们需要的所有列:

PIVOT (
    MAX(ColumnValue)
    FOR DateString IN (' + @dates + N')
) PIV

答案 1 :(得分:2)

这就是你要找的东西:

create table NameAndDate (NameCol varchar(200), DateCol datetime);

insert into NameAndDate (NameCol, DateCol) values ('A', '2010-03-04');
insert into NameAndDate (NameCol, DateCol) values ('B', '2010-03-05');

select * from NameAndDate;

select * from NameAndDate
pivot (
max(NameCol) 
for DateCol 
in ([2010-03-04], [2010-03-05])) 
as PivotResults;

这给了我以下结果:

   NameCol     DateCol
---------------------------------------
1  A           2010-03-04 00:00:00.0000
2  B           2010-03-05 00:00:00.0000


   2010-03-04  2010-03-05
-------------------------
1  A           B

请注意,这需要您在编写查询时提前知道日期(除非您使用Gabriel提到的动态SQL)。

编辑:

我尝试使用OMG Ponies的方法,但不得不像这样修改它:

declare @Dates nvarchar(max)
set @Dates = 
    (select '['+ convert(varchar, NameAndDate.DateCol) + '],' 
    from NameAndDate
    group by NameAndDate.DateCol
    order by NameAndDate.DateCol
    for xml path(''))
set @Dates = left(@Dates, len(@Dates) - 1)

declare @SQL nvarchar(4000)
set @SQL = 
    'select *  
    from NameAndDate
    pivot (
    max(NameCol) 
    for DateCol in (' + @Dates + ')) 
    as PivotResults'

exec sp_executesql @SQL

这给了我这些结果:

   Mar 4 2010 12:00AM   Mar 5 2010 12:00AM
------------------------------------------
1  A                    B

答案 2 :(得分:2)

使用:

DECLARE @SQL NVARCHAR(4000)
DECLARE @dates NVARCHAR(max)

SET @dates = SELECT '['+ t.date +"],"
               FROM TABLE t
           GROUP BY t.date
           ORDER BY t.date
            FOR XML PATH('')

@SQL = 'SELECT * 
          FROM TABLE 
         PIVOT(MAX(name) FOR date IN (@dates)) AS pvt'

BEGIN 

  EXEC sp_executesql @SQL, N'@dates NVARCHAR(max)', @dates

END