0

我会感谢一些帮助。我在名为 info_source 的 SQL Server 数据库中有一个表,其中包含以下数据:

Date        StatCode  Value_1  Value_2  Remarks
----------  --------  -------  -------  -------
2012-11-01  SRC_1     18775     648     Normal
2012-11-01  SRC_2     308218    249     Normal
2012-11-01  SRC_3     0         0       Off
2012-11-02  SRC_4     123181    523     Normal
2012-11-02  SRC_5     189231    247     Normal

我将使用statCode连接将字段替换为电台名称。我希望将转换为列的行用于报告中类似于以下内容:

Date       StatName   Value_1 Value_2 Remarks StatName   Value_1 Value_2 Remarks
---------- ---------- ------- ------- ------- ---------- ------- ------- -------
2012-11-01 (SRC_1)ABC 18775   648     Normal  (SRC_2)DEF 308218  249     Normal
2012-11-02 (SRC_4)JKL 123181  523     Normal  (SRC_5)MNO 189231  247     Normal

我打算创建一个视图,但无法解决问题。我研究并找到了一些关于数据透视表的信息,但我无法掌握如何编写一个符合我想要的查询。

编辑

这是我到目前为止所尝试的:

SELECT * FROM (
 SELECT date AS [date], statCode AS [station], value_1 AS [val1],
 value_2 AS [val2], remarks AS [remks] FROM info_source
) AS query1
4

1 回答 1

2

为了得到结果,我的建议是使用row_number()窗口函数,取消旋转列,statcode最后应用PIVOT 函数。value_1value_2remarks

第一步是查询您的数据并应用该row_number()功能。由于您在列中有多行数据,因此您需要一种方法来保持值相互关联:

select date, value_1, value_2, statcode, remarks,
  row_number() over(partition by date
                    order by statcode) seq
from yourtable;

请参阅演示。这将为表格中每个日期的每一行分配一个序列号。我使用了,order by statcode但是如果您有另一个值来将项目保持在特定顺序,那么您将使用该列。

分配行号后,您将取消透视、和列statcode中的数据。您可以使用 UNPIVOT 函数,也可以使用 CROSS APPLY 将多列转换为多行数据。当您转换数据时,您将留下 3 列、日期、前一列的值以及将在 PIVOT 中使用的新列名称:value_1value_2remarks

select date, 
  col = col+'_'+cast(seq as varchar(10)), 
  value
from
(
  select date, value_1, value_2, statcode, remarks,
    row_number() over(partition by date
                      order by statcode) seq
  from yourtable
) src
cross apply
(
  select 'statcode', statcode union all
  select 'value_1', cast(value_1 as varchar(10)) union all
  select 'value_2', cast(value_2 as varchar(10)) union all
  select 'remarks', remarks
) c (col, value);

请参阅演示。这将为您提供以下格式的数据:

|                            DATE |        COL |  VALUE |
---------------------------------------------------------
| November, 01 2012 00:00:00+0000 | statcode_1 |  SRC_1 |
| November, 01 2012 00:00:00+0000 |  value_1_1 |  18775 |
| November, 01 2012 00:00:00+0000 |  value_2_1 |    648 |
| November, 01 2012 00:00:00+0000 |  remarks_1 | Normal |
| November, 01 2012 00:00:00+0000 | statcode_2 |  SRC_2 |
| November, 01 2012 00:00:00+0000 |  value_1_2 | 308218 |

最后,您将对我调用的新列中的项目应用 PIVOT 函数col

select date,
  statcode_1, value_1_1, value_2_1, remarks_1,
  statcode_2, value_1_2, value_2_2, remarks_2,
  statcode_3, value_1_3, value_2_3, remarks_3
from
(
  select date, 
    col = col+'_'+cast(seq as varchar(10)), 
    value
  from
  (
    select date, value_1, value_2, statcode, remarks,
      row_number() over(partition by date
                        order by statcode) seq
    from yourtable
  ) src
  cross apply
  (
    select 'statcode', statcode union all
    select 'value_1', cast(value_1 as varchar(10)) union all
    select 'value_2', cast(value_2 as varchar(10)) union all
    select 'remarks', remarks
  ) c (col, value)
) d
pivot
(
  max(value)
  for col in (statcode_1, value_1_1, value_2_1, remarks_1,
              statcode_2, value_1_2, value_2_2, remarks_2,
              statcode_3, value_1_3, value_2_3, remarks_3)
) piv;

请参阅SQL Fiddle with Demo。现在,如果您有一个已知值,上面的代码将为您工作,但如果您有未知值,那么您将需要使用动态 SQL。动态SQL代码为:

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

select @cols = STUFF((SELECT ',' + QUOTENAME(col+'_'+cast(seq as varchar(10))) 
                    from 
                    (
                      select row_number() over(partition by date
                                                order by statcode) seq
                      from yourtable
                    ) t
                    cross apply
                    (
                      select 'statcode', 1 union all
                      select 'value_1', 2 union all
                      select 'value_2', 3 union all
                      select 'remarks', 4 
                    ) c (col, so)
                    group by col, seq, so
                    order by seq, so
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT date,' + @cols + ' 
            from 
            (
              select date, 
                col = col+''_''+cast(seq as varchar(10)), 
                value
              from
              (
                select date, value_1, value_2, statcode, remarks,
                  row_number() over(partition by date
                                    order by statcode) seq
                from yourtable
              ) src
              cross apply
              (
                select ''statcode'', statcode union all
                select ''value_1'', cast(value_1 as varchar(10)) union all
                select ''value_2'', cast(value_2 as varchar(10)) union all
                select ''remarks'', remarks
              ) c (col, value)
            ) x
            pivot 
            (
                max(value)
                for col in (' + @cols + ')
            ) p '

execute sp_executesql @query;

请参阅SQL Fiddle with Demo。两个版本都会给出结果:

|                            DATE | STATCODE_1 | VALUE_1_1 | VALUE_2_1 | REMARKS_1 | STATCODE_2 | VALUE_1_2 | VALUE_2_2 | REMARKS_2 | STATCODE_3 | VALUE_1_3 | VALUE_2_3 | REMARKS_3 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| November, 01 2012 00:00:00+0000 |      SRC_1 |     18775 |       648 |    Normal |      SRC_2 |    308218 |       249 |    Normal |      SRC_3 |         0 |         0 |       Off |
| November, 02 2012 00:00:00+0000 |      SRC_4 |    123181 |       523 |    Normal |      SRC_5 |    189231 |       247 |    Normal |     (null) |    (null) |    (null) |    (null) |
于 2013-08-01T18:23:47.893 回答