数据透视表有多个记录

时间:2014-03-20 14:22:41

标签: sql sql-server stored-procedures

我的数据结构如下:

LocationId, GroupId, DayOfWeek, Count,  DatetimeValue15Min
2            9         4         5      2014-01-02 08:15:00.000
2            9         4         5      2014-01-02 09:15:00.000    

我想计算每一天的模式,上面的数据已经包含了解模式的计数。我用一个数据库写了一个查询。

SELECT 
    pvt.LocationId, pvt.GroupId, [1], [2], [3], [4],[5]
FROM 
    @TempResult
PIVOT
    (min ([DatetimeValue15Min])
     FOR DayOfWeek IN ( [1], [2], [3], [4],[5])) AS pvt

在这种情况下,我有两种模式,但我想同时显示它们。在这种情况下,我的查询返回的是具有最小值的模式。我知道我可以用最大值进行第二次查询,但如果我有两种以上的模式呢?

输出应该是:

LocationId  GroupId    1          2           3       4               5
2             9                                       08:15, 09:15

我正在使用SQL Server 2005。

2 个答案:

答案 0 :(得分:1)

你快到了。您只需要构建以逗号分隔的列表。一个小的xml类型滥用对此非常有用。

;WITH
t1 AS ( --Add a grouping id for quick reference
  SELECT
    [LocationId],[GroupId],[DayOfWeek],[DatetimeValue15Min],
    DENSE_RANK() OVER(ORDER BY [LocationId],[GroupId],[DayOfWeek]) [i]
  FROM @TempResult
),
t2 AS ( --Build a comma-separated list of all [DatetimeValue15Min] with same grouping id
  SELECT [LocationId],[GroupId],[DayOfWeek],
    CAST(REPLACE((SELECT CONVERT(time, [DatetimeValue15Min]) AS a FROM t1 WHERE [i] = t.[i] FOR xml PATH('')),'</a><a>',',') AS xml).value('a[1]','varchar(max)') [dtv_list]
  FROM t1 t
)
SELECT pvt.LocationId, pvt.GroupId, [1], [2], [3], [4],[5]
                FROM t2

                PIVOT
                (
                    min ([dtv_list])
                    FOR DayOfWeek IN ( [1], [2], [3], [4],[5])
                ) AS pvt

xml技巧的作用如下:

  • SELECT [DatetimeValue15Min] FOR XML - &gt; <a>08:15</a><a>09:15</a>
  • '</a><a>'替换为',' - &gt; <a>08:15,09:15</a>
  • 从xml中提取第一个节点 - &gt; '08:15,09:15'

答案 1 :(得分:0)

SELECT LocationId, GroupId
    , STUFF (
          MAX (CASE WHEN DayOfWeek = 1 AND num = 1 THEN Value ELSE '' END)
        + MAX (CASE WHEN DayOfWeek = 1 AND num = 2 THEN Value ELSE '' END), 1, 2, '') AS [1]
    , STUFF (
          MAX (CASE WHEN DayOfWeek = 2 AND num = 1 THEN Value ELSE '' END)
        + MAX (CASE WHEN DayOfWeek = 2 AND num = 2 THEN Value ELSE '' END), 1, 2, '') AS [2]
    , STUFF (
          MAX (CASE WHEN DayOfWeek = 3 AND num = 1 THEN Value ELSE '' END)
        + MAX (CASE WHEN DayOfWeek = 3 AND num = 2 THEN Value ELSE '' END), 1, 2, '') AS [3]
    , STUFF (
          MAX (CASE WHEN DayOfWeek = 4 AND num = 1 THEN Value ELSE '' END)
        + MAX (CASE WHEN DayOfWeek = 4 AND num = 2 THEN Value ELSE '' END), 1, 2, '') AS [4]
    , STUFF (
          MAX (CASE WHEN DayOfWeek = 5 AND num = 1 THEN Value ELSE '' END)
        + MAX (CASE WHEN DayOfWeek = 5 AND num = 2 THEN Value ELSE '' END), 1, 2, '') AS [5]
FROM (
    SELECT LocationId, GroupId, DayOfWeek, ', ' + CONVERT (VARCHAR(5), DatetimeValue15Min, 8) AS Value
        , ROW_NUMBER() OVER(PARTITION BY LocationId, GroupId, DayOfWeek ORDER BY DatetimeValue15Min) AS num
    FROM @TempResult
) T
GROUP BY LocationId, GroupId

UPD。每天无限数量值的解决方案。

WITH cte AS (
    SELECT LocationId, GroupId, DayOfWeek, CONVERT (VARCHAR(5), DatetimeValue15Min, 8) AS Value
        , ROW_NUMBER() OVER(PARTITION BY LocationId, GroupId, DayOfWeek ORDER BY DatetimeValue15Min) AS num
    FROM @TempResult
)

SELECT LocationId, GroupId
    , MIN (CASE DayOfWeek WHEN 1 THEN Value END) AS [1]
    , MIN (CASE DayOfWeek WHEN 2 THEN Value END) AS [2]
    , MIN (CASE DayOfWeek WHEN 3 THEN Value END) AS [3]
    , MIN (CASE DayOfWeek WHEN 4 THEN Value END) AS [4]
    , MIN (CASE DayOfWeek WHEN 5 THEN Value END) AS [5]
FROM (
    SELECT DISTINCT c1.LocationId, c1.GroupId, c1.DayOfWeek
        , STUFF ( (
            SELECT ', ' + c2.Value
            FROM cte c2
            WHERE c1.LocationId = c2.LocationId AND c1.GroupId = c2.GroupId AND c1.DayOfWeek = c2.DayOfWeek
            FOR XML PATH ('')
        ), 1, 2, '') AS Value
    FROM cte c1
) t
GROUP BY LocationId, GroupId