SQL 数据透视表动态

Posted

技术标签:

【中文标题】SQL 数据透视表动态【英文标题】:SQL Pivot Table dynamic 【发布时间】:2015-01-21 13:56:08 【问题描述】:

我非常努力地了解如何在 SQL 中创建数据透视表,但我无法管理它!

我有以下列:

link_id   route_section   date_1    StartHour     AvJT    data_source
.......   .............  .......   ...........   ......  ............

拥有 600,000 行数据。

我需要它们在以下数据透视表中;

date_1 StartHour 作为列标题 link_id 作为行标题 AvJT作为数据 data_source = '1' 作为过滤器。

数据透视表

Link_ID 
date_1      StartHour    00001a    000002a    000003a    000004a
20/01/2014    8           456       4657        556       46576
21/01/2014    8           511       4725        601       52154
22/01/2014    8           468       4587        458       47585
23/01/2014    8           456       4657        556       46576
24/01/2014    8           456       4657        556       46576
25/01/2014    8           456       4657        556       46576
26/01/2014    8           456       4657        556       46576

我设法获得了以下代码,这有效,但只给了我 date_1 作为列标题,而不是额外的 StartHour,或者过滤器作为 date_source = '1'。

    Use [C1_20132014]

DECLARE @DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE @ColumnName AS NVARCHAR(MAX)

--Get distinct values of the PIVOT Column 
SELECT @ColumnName= ISNULL(@ColumnName + ',','') 
       + QUOTENAME(Link_ID)
FROM (SELECT DISTINCT Link_ID FROM C1_May_Routes) AS Link_ID

--Prepare the PIVOT query using the dynamic 
SET @DynamicPivotQuery = 
  N'SELECT Date_1, ' + @ColumnName + '
    FROM C1_May_Routes
    PIVOT(SUM(AvJT) 
          FOR Link_ID IN (' + @ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
EXEC sp_executesql @DynamicPivotQuery

感谢您的帮助,

亨利

【问题讨论】:

你能提供一个链接到它在其他地方被解决的地方吗? 我认为这个 - ***.com/questions/10404348/… 看到这个帖子:sqlhints.com/2014/03/18/dynamic-pivot-in-sql-server 总是有 4 列吗?如果是这样,您可以在交叉表中执行此操作,而无需使其动态化。 你如何在交叉表中做到这一点? @SeanLange 【参考方案1】:

您将在此处选择列中的值以显示为枢轴中的列

DECLARE @cols NVARCHAR (MAX)

SELECT @cols = COALESCE (@cols + ',[' + AvJT + ']', '[' + AvJT + ']')
               FROM    (SELECT DISTINCT AvJT FROM YourTable) PV  
               ORDER BY AvJT

现在旋转查询

DECLARE @query NVARCHAR(MAX)
SET @query = 'SELECT * FROM 
             (
                 SELECT date_1, StartHour,AvJT, data_source 
                 FROM YourTable
             ) x
             PIVOT 
             (
                 -- Values in each dynamic column
                 SUM(data_source)
                 FOR AvJT IN (' + @cols + ')                      
            ) p;' 

EXEC SP_EXECUTESQL @query
Click here查看结果

如果你想在列名不是动态的地方做,你可以做下面的查询

SELECT DATE_1,STARTHOUR,
MIN(CASE WHEN AvJT='00001a' THEN data_source END) [00001a],
MIN(CASE WHEN AvJT='00002a' THEN data_source END) [00002a],
MIN(CASE WHEN AvJT='00003a' THEN data_source END) [00003a],
MIN(CASE WHEN AvJT='00004a' THEN data_source END) [00004a]
FROM YOURTABLE
GROUP BY  DATE_1,STARTHOUR
Click here查看结果

编辑:

我正在更新您更新的问题。

声明一个用于过滤的变量data_source

DECLARE @DATASOURCE VARCHAR(20) = '1' 

除了QUOTENAME,您可以使用另一种格式来获取枢轴列

DECLARE @cols NVARCHAR (MAX)

SELECT @cols = COALESCE (@cols + ',[' + Link_ID + ']', '[' + Link_ID + ']')
               FROM    (SELECT DISTINCT Link_ID FROM C1_May_Routes WHERE data_source=@DATASOURCE) PV  
               ORDER BY Link_ID

现在旋转

DECLARE @query NVARCHAR(MAX)
SET @query = 'SELECT * FROM 
             (
                 -- We will select the data that has to be shown for pivoting
                 -- with filtered data_source
                 SELECT date_1, StartHour,AvJT, Link_ID
                 FROM C1_May_Routes
                 WHERE data_source = '+@DATASOURCE+'
             ) x
             PIVOT 
             (
                 -- Values in each dynamic column
                 SUM(AvJT)
                 -- Select columns from @cols 
                 FOR Link_ID IN (' + @cols + ')                      
            ) p;' 

EXEC SP_EXECUTESQL @query
Click here查看结果

【讨论】:

感谢您的回答,但我无法让它工作! 发生了什么?你面临的问题是什么? @hc91 我需要 AvJT 作为填充表格的数据。 Data_source 只需要一个过滤器,这样我就可以制作 4 个不同的表 - 源 1、源 2 等。这些应该是进入表的变量 - Date_1 smalldatetime、StartHour smallint、Link_ID VARCHAR(50)、AvJT int 你的意思是你想在某些日期之间像 Date_1 这样按日期过滤吗?@hc91 非常感谢!这很有帮助。【参考方案2】:

交叉表是这样的。 FWIW,我建议使用比 00001a 更好的列名。为您的列名赋予一些含义,以便它们更易于使用。

with SortedData as
(
    SELECT date_1
        , StartHour
        , AvJT
        , data_source 
        , ROW_NUMBER() over (partition by date_1 order by AvJT) AS RowNum
    FROM YourTable
)

select date_1
    , StartHour
    , MAX(case when RowNum = 1 then AvJT end) as [00001a]
    , MAX(case when RowNum = 2 then AvJT end) as [00002a]
    , MAX(case when RowNum = 3 then AvJT end) as [00003a]
    , MAX(case when RowNum = 4 then AvJT end) as [00004a]
from SortedData

【讨论】:

哦,我明白了,抱歉。列名是 link_id,大约有 6,000 个。

以上是关于SQL 数据透视表动态的主要内容,如果未能解决你的问题,请参考以下文章

SQL 中特定日期状态的动态数据透视表

SQL Server - 动态数据透视表 - SQL 注入

SQL - Oracle - 具有动态数据的数据透视表

SQL Server 中的动态数据透视表

SQL Server 中具有动态列的数据透视表

将 SQL 代码(作为字符串)转换为表 - 动态数据透视