SQL将一个表中的多个行组合成一个包含多个列的行

时间:2015-12-02 20:29:02

标签: sql sql-server-2008

如果我的数据的日期和时间相同或不同如下:

ID    Date               LOC
1     2015-12-02 10:05   A
1     2015-12-02 10:05   B2
2     2015-12-02 10:05   D
2     2015-12-02 10:05   A7P 
2     2015-12-02 10:06   AD

有没有办法显示以下内容:

ID   DATE1             LOC1  DATE 2            LOC2  DATE 3            LOC3
1    2015-12-02 10:05  A     2015-12-02 10:05  B2
2    2015-12-02 10:05  D     2015-12-02 10:05  A7P   
2    2015-12-02 10:06  AD

因此会有多行ID,但日期和时间不同?

我使用了下面的分区示例,这非常适合将数据放入我最初提出的一行中。但是当ID相同但日期和时间不同时,是否可以显示多行。

以下是已经得到回答的原始问题..

我看过所有与此问题相关的答案,但无法找到任何有效的代码,而且很多问题都与两个表有关。

我有一个包含多行数据的表和多个包含不同数据类型的列,例如

ID    Date               LOC
1     2015-11-05 10:05   A
1     2015-12-02 10:06   B2
2     2015-12-02 10:05   D
2     2015-12-02 10:05   A7P 
2     2015-12-02 10:06   AD

对于每个ID,我只需要一行,所有数据都在多列中,例如

ID   DATE1             LOC1  DATE 2            LOC2  DATE 3            LOC3
1    2015-11-05 10:05  A     2015-12-02 10:06  B2
2    2015-12-02 10:05  D     2015-12-02 10:05  A7P   2015-12-02 10:06  AD

这些可以包含重复的数据和一个或多个相同ID的行。

我尝试了一些pivot / unpivot sql代码但是我收到了关于unpivot中不同类型的错误。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

这是解决此问题的基本方法,首先制作row_number,然后再进行连接

WITH TAB_RN AS
(
  SELECT ID, Date, LOC, ROW_NUMBER() OVER (PARTITION BY ID, Date ORDER BY LOC) AS RN
  FROM YOUR_TABLE
)
SELECT T1.ID, 
       T1.Date AS DATE1, T1.LOC AS LOC1,
       T2.Date AS DATE2, T2.LOC AS LOC2,
       T3.Date AS DATE3, T3.LOC AS LOC3
FROM TAB_RN T1
LEFT JOIN TAB_RN T2 ON T1.ID = T2.ID AND T1.Date = T2.Date AND T2.RN = 2
LEFT JOIN TAB_RN T3 ON T1.ID = T3.ID AND T1.Date = T2.Date AND T3.RN = 3
WHERE T1.RN = 1

如果你不知道"有多少"然后你必须使用它作为模板来制作动态sql。

答案 1 :(得分:0)

我想我已经设法得到了这个,但我不确定这个是否有错误。

我为测试目的创建了一个示例表

CREATE TABLE Trace (
    TraceID INT IDENTITY(1,1)
    , ID INT
    , [Date] DATETIME
    , LOC NVARCHAR(50)
)

INSERT INTO Trace (ID, [Date], LOC)
VALUES
(1,'2015-12-02 10:05','A'),
(1,'2015-12-02 10:05','B2'),
(2,'2015-12-02 10:05','D'),
(2,'2015-12-02 10:05','A7P'),
(2,'2015-12-02 10:06','AD')

如果您希望根据每个ID的最大位置数(灵活列)获取记录,您可以尝试下面的脚本。

   -- build up table to keep the values in 1 column and make a flag (StatusCode) out of it
        SELECT 
            ROW_NUMBER() OVER (PARTITION BY ID, StatusCode ORDER BY TraceID, Pos) AS idx
            , *
        INTO #resultBuildUp 
        FROM (
                SELECT
                    TraceID
                    , 2 AS [Pos]
                    , [ID]
                    , 'LOC' + CONVERT(NVARCHAR(50),(ROW_NUMBER() OVER (PARTITION BY ID, [Date] ORDER BY TraceID))) AS StatusCode
                    , LOC AS [val]
                FROM Trace
            UNION ALL
                SELECT
                    TraceID
                    , 1 AS [Pos]
                    , [ID]
                    , 'DATE ' + CONVERT(NVARCHAR(50),(ROW_NUMBER() OVER (PARTITION BY ID, [Date] ORDER BY TraceID))) AS StatusCode
                    , REPLACE(CONVERT(NVARCHAR(50),[Date],111),'/','-') + ' ' + CONVERT(NVARCHAR(50),[Date],108) AS [val]
                FROM Trace
        ) AS T

    --this is a builder to create the "select" columns for PIVOT

        SELECT
            StatusCode
        INTO #tmpDistinctColumns
        FROM #resultBuildUp
        GROUP BY
            StatusCode
        ORDER BY 
            min(TraceID)
            , min(Pos)

        DECLARE @distinct NVARCHAR(MAX) = ''

        SET @distinct = (SELECT '[' + StatusCode + '],' AS [text()] FROM #tmpDistinctColumns FOR XML PATH(''))
        SET @distinct = SUBSTRING(@distinct, 0, LEN(@distinct))

-- and lastly, the pivot query wherein I hid the position modifier(idx) for the query

EXEC ('
SELECT
    ID
    , ' + @distinct + '
FROM (
    SELECT
        idx,
        ID,
        StatusCode,
        val
    FROM #resultBuildUp
) AS s 
PIVOT
(
    MAX(Val)
    FOR StatusCode IN (' + @distinct + ')
) AS pvt
')

-- drop all temporary tables built from above script
drop table #resultBuildUp
drop table #tmpDistinctColumns

您的要求中指定的“时间”也已被考虑,结果应如下所示

enter image description here