SQL - 将多行数据转换为单行

时间:2013-04-17 09:34:42

标签: sql sql-server sql-server-2005

我有一张类似于此处的表格:

SetId       AppCode       AppEventId       EventId       FieldId       ValueData
2012/2013     1000         361616             16            1            UNI     
2012/2013     1000         361616             16            2            Isolation
2012/2013     1000         361616             16            3            DN
2012/2013     1050         378194             16            1            BUL
2012/2013     1050         378194             16            2            Isolation
2012/2013     1050         378194             16            3            RD

我希望能够在拥有相同的AppCode时合并所有数据。

看起来像这样:

SetId       AppCode       AppEventId       EventId       ValueData1      ValueData2      ValueData3
2012/2013     1000         361616             16            UNI            Isolation        DN
2012/2013     1050         378194             16            BUL            Isolation        RD

3 个答案:

答案 0 :(得分:14)

试试这个

  SELECT SetId, AppCode, AppEventId, EventId 
  ,max(CASE WHEN FieldId = 1 THEN ValueData END) AS ValueData1
  ,max(CASE WHEN FieldId = 2 THEN ValueData END) AS ValueData2
  ,max(CASE WHEN FieldId = 3 THEN ValueData END) AS ValueData3
   FROM Table_Name 
   GROUP BY SetId,AppCode,AppEventId,EventId 

答案 1 :(得分:7)

这可以通过应用从SQL Server 2005开始提供的PIVOT函数来完成。

如果您要将已知或设定数量的值转换为列,则可以对查询进行硬编码:

select setid, appcode, appeventid,
  eventid,
  ValueData1, ValueData2, ValueData3
from
(
  select setid, appcode, appeventid,
    eventid,
    'ValueData'+cast(FieldId as varchar(10)) FieldId, 
    ValueData
  from yt
) d
pivot
(
  max(ValueData)
  for FieldId in (ValueData1, ValueData2, ValueData3)
) piv;

请参阅SQL Fiddle with Demo

但是如果你有一个未知数量的值,那么你将需要使用动态SQL:

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

select @cols = STUFF((SELECT distinct ',' + QUOTENAME('ValueData'+cast(FieldId as varchar(10))) 
                    from yt
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT setid, appcode, appeventid,
                  eventid,' + @cols + ' 
            from 
            (
                select setid, appcode, appeventid,
                  eventid,
                  ''ValueData''+cast(FieldId as varchar(10)) FieldId, 
                  ValueData
                from yt
            ) x
            pivot 
            (
                max(ValueData)
                for FieldId in (' + @cols + ')
            ) p '

execute(@query);

SQL Fiddle with Demo。两个查询都给出了相同的结果:

|     SETID | APPCODE | APPEVENTID | EVENTID | VALUEDATA1 | VALUEDATA2 | VALUEDATA3 |
-------------------------------------------------------------------------------------
| 2012/2013 |    1000 |     361616 |      16 |        UNI |  Isolation |         DN |
| 2012/2013 |    1050 |     378194 |      16 |        BUL |  Isolation |         RD |

答案 2 :(得分:2)

<强>更新

改善答案 -

DECLARE @temp TABLE
(
        SetId VARCHAR(9)       
      , AppCode CHAR(4)      
      , AppEventId INT      
      , EventId INT      
      , FieldId TINYINT      
      , ValueData VARCHAR(50)
)

INSERT INTO @temp (SetId, AppCode, AppEventId, EventId, FieldId, ValueData)
VALUES 
    ('2012/2013',     '1000',         361616,             16,            1,            'UNI'),    
    ('2012/2013',     '1000',         361616,             16,            2,            'Isolation'),
    ('2012/2013',     '1000',         361616,             16,            3,            'DN'),
    ('2012/2013',     '1050',         378194,             16,            1,            'BUL'),
    ('2012/2013',     '1050',         378194,             16,            2,            'Isolation'),
    ('2012/2013',     '1050',         378194,             16,            3,            'RD')

;WITH tbl AS 
(
    SELECT  
            PK = t.SetId + t.AppCode + CAST(AppEventId AS VARCHAR(10)) + CAST(EventId AS VARCHAR(5))
          , t.SetId
          , t.AppCode
          , t.AppEventId
          , t.EventId
          , t.FieldId
          , t.ValueData
    FROM @temp t
) 
SELECT DISTINCT 
      t.SetId
    , t.AppCode
    , t.AppEventId
    , t.EventId
    , t2.ValueData
    , t3.ValueData
    , t4.ValueData
FROM tbl t
JOIN tbl t2 ON t.PK = t2.PK AND t2.FieldId = 1
JOIN tbl t3 ON t.PK = t3.PK AND t3.FieldId = 2
JOIN tbl t4 ON t.PK = t4.PK AND t4.FieldId = 3

不优雅,但有效 -

DECLARE @temp TABLE
(
        SetId VARCHAR(9)       
      , AppCode CHAR(4)      
      , AppEventId INT      
      , EventId INT      
      , FieldId TINYINT      
      , ValueData VARCHAR(50)
)

INSERT INTO @temp (SetId, AppCode, AppEventId, EventId, FieldId, ValueData)
VALUES 
    ('2012/2013',     '1000',         361616,             16,            1,            'UNI'),    
    ('2012/2013',     '1000',         361616,             16,            2,            'Isolation'),
    ('2012/2013',     '1000',         361616,             16,            3,            'DN'),
    ('2012/2013',     '1050',         378194,             16,            1,            'BUL'),
    ('2012/2013',     '1050',         378194,             16,            2,            'Isolation'),
    ('2012/2013',     '1050',         378194,             16,            3,            'RD')

SELECT  t.SetId
    ,   t.AppCode
    ,   t.AppEventId
    ,   t.EventId
    ,   t2.ValueData
    ,   t3.ValueData
    ,   t4.ValueData
FROM (
    SELECT  
          t.SetId
        , t.AppCode
        , t.AppEventId
        , t.EventId
        , FieldId1 = MAX(CASE WHEN t.FieldId = 1 THEN t.FieldId END)
        , FieldId2 = MAX(CASE WHEN t.FieldId = 2 THEN t.FieldId END)
        , FieldId3 = MAX(CASE WHEN t.FieldId = 3 THEN t.FieldId END)
    FROM @temp t
    GROUP BY 
          t.SetId
        , t.AppCode
        , t.AppEventId
        , t.EventId
) t
JOIN @temp t2 ON t.SetId = t2.SetId
        AND t.AppCode = t2.AppCode
        AND t.AppEventId = t2.AppEventId
        AND t.EventId = t2.EventId
        AND t2.FieldId = 1
JOIN @temp t3 ON t.SetId = t3.SetId
        AND t.AppCode = t3.AppCode
        AND t.AppEventId = t3.AppEventId
        AND t.EventId = t3.EventId
        AND t3.FieldId = 2
JOIN @temp t4 ON t.SetId = t4.SetId
        AND t.AppCode = t4.AppCode
        AND t.AppEventId = t4.AppEventId
        AND t.EventId = t4.EventId
        AND t4.FieldId = 3