将多行聚合到新的单个长行数据中

时间:2014-07-09 09:59:38

标签: sql pivot aggregate

我有一个数据库,每个" case"有很多行数据。每个"案例"具有唯一的ID,但每行都有一个" multiple-choice-element"和"价值"。每当用户选择多个选择元素之一(mce)和新值时,显然会有一个新行。唯一ID就像一个linchpin,将所有行保存在一起作为此实例的公共元素

数据如下:

UniqueID  Value      Text       Username     Contact
--------------------------------------------------
123456    No Sound   Horn       Johnson      0788
123456    Broken     Headlight  Johnson      0788
123456    Broken     Windscreen Johnson      0788

我希望只保留一行数据,用户详细信息,密钥(唯一ID),然后为每个mce和每个值设置多个列。

UniqueID Username  Contact   Text  Value      Text      Value   Text       Value
---------------------------------------------------------------------------------
123456   Johnson   0788      Horn  No Sound   Headlight Broken  Windscreen Broken

到目前为止,我已经使用基于唯一ID的每个mce的更新语句来完成此操作,但它有点笨拙且长时间作为存储过程,并且可能需要相当长的时间才能运行。 / p>

请有人建议更好的方式。

谢谢。

1 个答案:

答案 0 :(得分:0)

编辑2:我甚至不确定这是可能的,但我想我已经找到了办法。不幸的是,它非常hacky,因为你从未发布过你的RDBMS标签,我甚至不知道它是否适合你。

我并不是特别喜欢这个解决方案,就像我说的那样 - 这对我来说很笨拙,但确实有效,而且我没有时间专心致志这个问题。除非别人能找到一种方法让它更有效地工作,否则这是我能为你做的最好的事情。请注意,我创建并引用了一个名为#Numbers的临时表 - 您需要将其保留在查询中。另请注意,您可能会得到比您想要的更多的列,但这必须保留。

以下脚本允许您转动两列,保留第1列(Txt)中不同值与第2列(值)中的多个值之间的关系

CREATE TABLE #Data (UniqueID INT, Value varchar(10), Txt varchar(10), Username varchar(10), Contact INT)
INSERT INTO #Data (UniqueID, Value, Txt, Username, Contact) 

SELECT 123456, 'No Sound', 'Horn', 'Johnson', 0788 UNION
SELECT 123456, 'Broken', 'Headlight', 'Johnson', 0788 UNION
SELECT 123456, 'Smashed', 'Headlight', 'Johnson', 0788 UNION
SELECT 123456, 'Shattered', 'Headlight', 'Johnson', 0788 UNION
SELECT 123456, 'Busted', 'Headlight', 'Johnson', 0788 UNION
SELECT 123456, 'Inop', 'Brake', 'Johnson', 0788 

DECLARE @sql AS varchar(max)
DECLARE @vpivot_list AS varchar(max) -- Leave NULL for COALESCE technique
DECLARE @vselect_list AS varchar(max) -- Leave NULL for COALESCE technique
DECLARE @tpivot_list AS varchar(max) -- Leave NULL for COALESCE technique
DECLARE @tselect_list AS varchar(max) -- Leave NULL for COALESCE technique



CREATE TABLE #Numbers (Number INT) 
;WITH NumberSequence( Number ) AS
  (
    SELECT 1 as Number
    UNION ALL 
    SELECT Number + 1
    FROM NumberSequence
    WHERE Number < 100
  )
INSERT INTO #Numbers (Number)
SELECT Number FROM NumberSequence




SELECT 
    @vpivot_list = COALESCE(@vpivot_list + ', ', '') + '[' + TxtValCombinations + ']'
FROM
  (
    SELECT 
        'T' + CAST(Txt.Number AS VARCHAR(5)) + '_' + 
        'V' + CAST(Val.Number AS VARCHAR(5))  AS TxtValCombinations
    FROM 
        #Numbers Txt
         INNER JOIN 
          (
            SELECT MAX(CountTxt) MaxCountTxt
            FROM
              (
                SELECT COUNT(DISTINCT Txt) CountTxt
                FROM #Data
                GROUP BY UniqueID 
              ) cv
          ) MaxCountTxt ON 
            Txt.Number <= MaxCountTxt.MaxCountTxt
         INNER JOIN 
        #Numbers Val ON 
            Val.Number < 
              (
                SELECT MAX(CountValue) MaxCountValue
                FROM
                  (
                    SELECT COUNT(Value) CountValue
                    FROM #Data
                    GROUP BY UniqueID, Txt
                  ) cv
              )
  ) PossibleValues


SELECT 
    @tpivot_list = COALESCE(@tpivot_list + ', ', '') + '[' + TxtCombinations + ']'
FROM
  (
    SELECT 
        'T' + CAST(Txt.Number AS VARCHAR(5)) AS TxtCombinations
    FROM 
        #Numbers Txt
         INNER JOIN 
          (
            SELECT MAX(CountTxt) MaxCountTxt
            FROM
              (
                SELECT COUNT(DISTINCT Txt) CountTxt
                FROM #Data
                GROUP BY UniqueID 
              ) cv
          ) MaxCountTxt ON 
            Txt.Number <= MaxCountTxt.MaxCountTxt
  ) PossibleValues

SELECT @vselect_list = STUFF(
  (
    SELECT',' + 
        'T' + CAST(Txt.Number AS VARCHAR(5)) + '_' + 
        'V' + CAST(Val.Number AS VARCHAR(5))  --AS TxtValCombinations
    FROM 
        #Numbers Txt
         INNER JOIN 
          (
            SELECT MAX(CountTxt) MaxCountTxt
            FROM
              (
                SELECT COUNT(DISTINCT Txt) CountTxt
                FROM #Data
                GROUP BY UniqueID 
              ) cv
          ) MaxCountTxt ON 
            Txt.Number <= MaxCountTxt.MaxCountTxt
         INNER JOIN 
        #Numbers Val ON 
            Val.Number < 
              (
                SELECT MAX(CountValue) MaxCountValue
                FROM
                  (
                    SELECT COUNT(Value) CountValue
                    FROM #Data
                    GROUP BY UniqueID, Txt
                  ) cv
              )
    ORDER BY Txt.Number, Val.Number
     FOR XML PATH(''), type
        ).value('.', 'varchar(max)'), 1, 1, '')

 SELECT @tselect_list = STUFF(
  (

    SELECT TxtValCombinations
    FROM 
     (
        SELECT',MAX(' + 
            'T' + CAST(Txt.Number AS VARCHAR(5)) + '_' + 
            'V' + CAST(Val.Number AS VARCHAR(5)) + ') AS '+ 
            'T' + CAST(Txt.Number AS VARCHAR(5)) + '_' + 
            'V' + CAST(Val.Number AS VARCHAR(5))  AS TxtValCombinations
        FROM 
            #Numbers Txt
             INNER JOIN 
              (
                SELECT MAX(CountTxt) MaxCountTxt
                FROM
                  (
                    SELECT COUNT(DISTINCT Txt) CountTxt
                    FROM #Data
                    GROUP BY UniqueID 
                  ) cv
              ) MaxCountTxt ON 
                Txt.Number <= MaxCountTxt.MaxCountTxt
             INNER JOIN 
            #Numbers Val ON 
                Val.Number < 
                  (
                    SELECT MAX(CountValue) MaxCountValue
                    FROM
                      (
                        SELECT COUNT(Value) CountValue
                        FROM #Data
                        GROUP BY UniqueID, Txt
                      ) cv
                  )

        UNION ALL 
        SELECT',MAX(' + 
            'T' + CAST(Txt.Number AS VARCHAR(5)) +') AS T' + CAST(Txt.Number AS VARCHAR(5))  --AS TxtValCombinations
        FROM 
            #Numbers Txt
             INNER JOIN 
              (
                SELECT MAX(CountTxt) MaxCountTxt
                FROM
                  (
                    SELECT COUNT(DISTINCT Txt) CountTxt
                    FROM #Data
                    GROUP BY UniqueID 
                  ) cv
              ) MaxCountTxt ON 
                Txt.Number <= MaxCountTxt.MaxCountTxt

     ) s
        ORDER BY TxtValCombinations
     FOR XML PATH(''), type
        ).value('.', 'varchar(max)'), 1, 1, '')



SET @sql = '

SELECT UniqueID, Username, Contact, ' + @tselect_list + '
FROM 
  (

    SELECT UniqueID, Username, Contact, Txt, tPIVOT_CODE, ' + @vselect_list + '
    FROM 
      (
        SELECT b.UniqueID, Value, Username, Contact, Txt, tPIVOT_CODE, vPIVOT_CODE
        FROM 
              (
                SELECT 
                    Data.UniqueID,  
                    Data.Username, 
                    Data.Contact, 
                    Data.Txt,
                    ''T'' + CAST(grpTxt.TxtNum AS VARCHAR(5)) AS tPIVOT_CODE, 
                    Data.Value,
                    ''T'' + CAST(grpTxt.TxtNum AS VARCHAR(5)) + ''_V'' + CAST(ROW_NUMBER() OVER (PARTITION BY Data.UniqueID, Data.Txt ORDER BY Data.Value) AS VARCHAR(4)) vPIVOT_CODE 
                FROM 
                    #Data Data
                     INNER JOIN 
                      (
                        SELECT UniqueID, Txt, ROW_NUMBER() OVER (PARTITION BY UniqueID ORDER BY Txt) AS TxtNum
                        FROM #Data
                        GROUP BY UniqueID, Txt
                      ) grpTxt ON 
                        Data.UniqueID = grpTxt.UniqueID AND
                        Data.Txt = grpTxt.Txt

              ) b
      ) vp
    PIVOT (
        MIN(Value)
        FOR vPIVOT_CODE IN (
            ' + @vpivot_list + '
        )
    ) AS vpvt
  ) tp
PIVOT (
    MIN(Txt)
    FOR tPIVOT_CODE IN (
        ' + @tpivot_list + '
    )
) AS tpvt
GROUP BY UniqueID, UserName, Contact
ORDER BY UniqueID, UserName, Contact
'


--PRINT @sql
--PRINT @tselect_list
--PRINT @vpivot_list
EXEC (@sql)

DROP TABLE #Data
DROP TABLE #Numbers