Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL Server 2008:在多个列上旋转_Sql_Sql Server 2008_Pivot - Fatal编程技术网

SQL Server 2008:在多个列上旋转

SQL Server 2008:在多个列上旋转,sql,sql-server-2008,pivot,Sql,Sql Server 2008,Pivot,需要有关SQL Server 2008中pivot子句的帮助。我有一张包含以下信息的表格: 我的表格有9列:ID,Period\u 1到Period\u 4作为日期(即2013-04、2013-07等)和Amount\u 1到Amount\u 4(即30、40等)。我希望从期间1到期间4的所有不同日期都作为列名,然后透视期间1对应的金额1,期间2对应的金额2,Amount\u 3对应于Period\u 3和Amount\u 4对应于Period\u 4作为行值 这是我目前提出的T-SQL: DE

需要有关SQL Server 2008中pivot子句的帮助。我有一张包含以下信息的表格:

我的表格有9列:
ID
Period\u 1
Period\u 4
作为日期(即2013-04、2013-07等)和
Amount\u 1
Amount\u 4
(即30、40等)。我希望从
期间1
期间4
的所有不同日期都作为列名,然后透视
期间1
对应的
金额1
期间2
对应的
金额2
Amount\u 3
对应于
Period\u 3
Amount\u 4
对应于
Period\u 4
作为行值

这是我目前提出的T-SQL:

DECLARE @cols AS NVARCHAR(MAX)
,@query AS NVARCHAR(MAX)

SELECT @cols = STUFF((
        SELECT DISTINCT ',' + QUOTENAME(ans)
        FROM (
            SELECT Period_1 AS ans
            FROM Booking

            UNION

            SELECT Period_2 AS ans
            FROM Booking

            UNION

            SELECT Period_3 AS ans
            FROM Booking

            UNION

            SELECT Period_4 AS ans
            FROM Booking
            ) a
        FOR XML PATH('')
            ,TYPE
        ).value('.', 'NVARCHAR(MAX)'), 1, 1, '')

SET @query = 'SELECT Id ' + @cols + ' from 
         (
            select Id, Period_1, Amount_1, Period_2, Amount_2
            from Booking
         ) x
        pivot 
        (
            max(Amount_1)
            for Period_1 in (' + @cols + ')

        ) p 
(
            max(Amount_2)
            for Period_2 in (' + @cols + ')

        ) p

        '

EXECUTE (@query)
我得到了一个错误:

Msg 265,第16级,状态1,第18行
PIVOT运算符中指定的列名“2013-10”与PIVOT参数中的现有列名冲突

有没有办法对包含相同值的多个列执行透视查询?请写一个如何做的例子来回应


我非常感谢你在这方面的帮助。提前谢谢

我认为您必须在字段名中添加一些内容,并为您使用的每个值创建一个
@cols
变量,即:

SELECT @cols1 = STUFF((
        SELECT DISTINCT ',' + QUOTENAME(ans)
        FROM (SELECT '1_'+CAST(Period_1  AS VARCHAR(12)) AS ans
              FROM #test
              UNION
              SELECT '1_'+CAST(Period_2  AS VARCHAR(12)) AS ans
              FROM #test
            ) a
        FOR XML PATH(''),TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1,'')
        ,@cols2 = STUFF((
                SELECT DISTINCT ',' + QUOTENAME(ans)
                FROM (SELECT '2_'+CAST(Period_1 AS VARCHAR(12)) AS ans
                      FROM #test
                      UNION
                      SELECT '2_'+CAST(Period_2 AS VARCHAR(12)) AS ans
                      FROM #test
                    ) a
                FOR XML PATH(''),TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1,'')
然后在数据透视时引用相应的变量,您还必须在字段名称中添加:

(
    max(Amount_1)
    for '1_'+CAST(Period_1 AS VARCHAR(12)) in (' + @cols1 + ')

) p 

可能有一种更聪明的方法可以做到这一点,但我不知道有一种。

我认为您必须在字段名中添加一些内容,并为您使用的每个值创建一个
@cols
变量,即:

SELECT @cols1 = STUFF((
        SELECT DISTINCT ',' + QUOTENAME(ans)
        FROM (SELECT '1_'+CAST(Period_1  AS VARCHAR(12)) AS ans
              FROM #test
              UNION
              SELECT '1_'+CAST(Period_2  AS VARCHAR(12)) AS ans
              FROM #test
            ) a
        FOR XML PATH(''),TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1,'')
        ,@cols2 = STUFF((
                SELECT DISTINCT ',' + QUOTENAME(ans)
                FROM (SELECT '2_'+CAST(Period_1 AS VARCHAR(12)) AS ans
                      FROM #test
                      UNION
                      SELECT '2_'+CAST(Period_2 AS VARCHAR(12)) AS ans
                      FROM #test
                    ) a
                FOR XML PATH(''),TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1,'')
然后在数据透视时引用相应的变量,您还必须在字段名称中添加:

(
    max(Amount_1)
    for '1_'+CAST(Period_1 AS VARCHAR(12)) in (' + @cols1 + ')

) p 

可能有一种更聪明的方法可以做到这一点,但我不知道。

你的部分问题是你的数据没有标准化,有
句点1
金额1
句点2
金额2
等列使得查询你的数据非常困难。我的第一个建议是考虑将表结构固定到与以下类似的东西:

create table booking
(
  id int,
  period datetime,
  amount decimal(10, 5)
);
这将允许您为每个id设置多个期间和金额。有其他方法可以设计,但这将让您了解如何修复当前结构

如果您无法修复结构,那么我建议对现有表应用UNPIVOT和PIVOT。UNPIVOT会将多列数据转换为多行,然后您可以将数据透视应用于金额以获得最终结果

UNPIVOT的基本语法如下所示。我使用工会交叉申请,因为我们需要同时取消期限和金额:

select id, 
  convert(varchar(7), period, 120) period,
  amount
from
(
  select id, 
    period_1, period_2, period_3, period_4,
    amount_1, amount_2, amount_3, amount_4
  from booking
) d
cross apply
(
  select period_1, amount_1 union all
  select period_2, amount_2 union all
  select period_3, amount_3 union all
  select period_4, amount_4
) c (period, amount);
看。这将为您提供以下格式的数据:

| ID |  PERIOD | AMOUNT |
-------------------------
|  1 | 2013-01 |     30 |
|  1 | 2013-04 |     40 |
|  1 | 2013-07 |     50 |
|  1 | 2013-10 |     60 |
数据采用此格式后,您可以将透视函数应用于
Period
列中的值:

select id,
  [2013-01], [2013-04], [2013-05],
  [2013-07], [2013-08], [2013-10],
  [2013-11]
from
(
  select id, 
    convert(varchar(7), period, 120) period,
    amount
  from
  (
    select id, 
      period_1, period_2, period_3, period_4,
      amount_1, amount_2, amount_3, amount_4
    from booking
  ) d
  cross apply
  (
    select period_1, amount_1 union all
    select period_2, amount_2 union all
    select period_3, amount_3 union all
    select period_4, amount_4
  ) c (period, amount)
) src
pivot
(
  sum(amount)
  for period in ([2013-01], [2013-04], [2013-05],
                 [2013-07], [2013-08], [2013-10],
                 [2013-11])
) piv;
看。当然,如果你提前知道这些价值观,上述方法将非常有效。但是如果您不这样做,那么您将希望使用动态SQL来获得结果:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(period) 
                    from 
                    (
                      select convert(varchar(7), period_1, 120) period, period_1 dt 
                      from booking union all
                      select convert(varchar(7), period_2, 120) period, period_2 dt
                      from booking union all
                      select convert(varchar(7), period_3, 120) period, period_3 dt
                      from booking union all
                      select convert(varchar(7), period_4, 120) period, period_4
                      from booking
                    ) d
                    group by period, dt
                    order by dt
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT id, ' + @cols + ' 
            from
            (
              select id, 
                convert(varchar(7), period, 120) period,
                amount
              from
              (
                select id, 
                  period_1, period_2, period_3, period_4,
                  amount_1, amount_2, amount_3, amount_4
                from booking
              ) d
              cross apply
              (
                select period_1, amount_1 union all
                select period_2, amount_2 union all
                select period_3, amount_3 union all
                select period_4, amount_4
              ) c (period, amount)
            ) src
            pivot 
            (
                sum(amount)
                for period in (' + @cols + ')
            ) p '

execute(@query);
看。这些查询将产生类似以下结果:

| ID | 2013-01 | 2013-04 | 2013-05 | 2013-07 | 2013-08 | 2013-10 | 2013-11 |
----------------------------------------------------------------------------
|  1 |     105 |      40 |      86 |      50 |     120 |      60 |      65 |

问题的一部分是您的数据没有标准化,具有
Period\u 1
Amount\u 1
Period\u 2
Amount\u 2
等列的数据查询非常困难。我的第一个建议是考虑将表结构固定到与以下类似的东西:

create table booking
(
  id int,
  period datetime,
  amount decimal(10, 5)
);
这将允许您为每个id设置多个期间和金额。有其他方法可以设计,但这将让您了解如何修复当前结构

如果您无法修复结构,那么我建议对现有表应用UNPIVOT和PIVOT。UNPIVOT会将多列数据转换为多行,然后您可以将数据透视应用于金额以获得最终结果

UNPIVOT的基本语法如下所示。我使用工会交叉申请,因为我们需要同时取消期限和金额:

select id, 
  convert(varchar(7), period, 120) period,
  amount
from
(
  select id, 
    period_1, period_2, period_3, period_4,
    amount_1, amount_2, amount_3, amount_4
  from booking
) d
cross apply
(
  select period_1, amount_1 union all
  select period_2, amount_2 union all
  select period_3, amount_3 union all
  select period_4, amount_4
) c (period, amount);
看。这将为您提供以下格式的数据:

| ID |  PERIOD | AMOUNT |
-------------------------
|  1 | 2013-01 |     30 |
|  1 | 2013-04 |     40 |
|  1 | 2013-07 |     50 |
|  1 | 2013-10 |     60 |
数据采用此格式后,您可以将透视函数应用于
Period
列中的值:

select id,
  [2013-01], [2013-04], [2013-05],
  [2013-07], [2013-08], [2013-10],
  [2013-11]
from
(
  select id, 
    convert(varchar(7), period, 120) period,
    amount
  from
  (
    select id, 
      period_1, period_2, period_3, period_4,
      amount_1, amount_2, amount_3, amount_4
    from booking
  ) d
  cross apply
  (
    select period_1, amount_1 union all
    select period_2, amount_2 union all
    select period_3, amount_3 union all
    select period_4, amount_4
  ) c (period, amount)
) src
pivot
(
  sum(amount)
  for period in ([2013-01], [2013-04], [2013-05],
                 [2013-07], [2013-08], [2013-10],
                 [2013-11])
) piv;
看。当然,如果你提前知道这些价值观,上述方法将非常有效。但是如果您不这样做,那么您将希望使用动态SQL来获得结果:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(period) 
                    from 
                    (
                      select convert(varchar(7), period_1, 120) period, period_1 dt 
                      from booking union all
                      select convert(varchar(7), period_2, 120) period, period_2 dt
                      from booking union all
                      select convert(varchar(7), period_3, 120) period, period_3 dt
                      from booking union all
                      select convert(varchar(7), period_4, 120) period, period_4
                      from booking
                    ) d
                    group by period, dt
                    order by dt
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT id, ' + @cols + ' 
            from
            (
              select id, 
                convert(varchar(7), period, 120) period,
                amount
              from
              (
                select id, 
                  period_1, period_2, period_3, period_4,
                  amount_1, amount_2, amount_3, amount_4
                from booking
              ) d
              cross apply
              (
                select period_1, amount_1 union all
                select period_2, amount_2 union all
                select period_3, amount_3 union all
                select period_4, amount_4
              ) c (period, amount)
            ) src
            pivot 
            (
                sum(amount)
                for period in (' + @cols + ')
            ) p '

execute(@query);
看。这些查询将产生类似以下结果:

| ID | 2013-01 | 2013-04 | 2013-05 | 2013-07 | 2013-08 | 2013-10 | 2013-11 |
----------------------------------------------------------------------------
|  1 |     105 |      40 |      86 |      50 |     120 |      60 |      65 |

谢谢你的回答!谢谢你的回答!