将行数据转换为sql server 2008中的列

Convert rows data into column in sqlserver 2008

在下面的情况下,我有 2 条记录,但每个 ID 的编号或记录不固定...

SELECT InsuredMemberIdentifier,CoverageStartDate,CoverageEndDate FROM     
APCD.DBO.EdgeServer_EligibilityConsolidated_Part3 WHERE
InsuredMemberIdentifier=10190

输出是:

InsuredMemberIdentifier | CoverageStartDate |   CoverageEndDate
10190                      2014-01-01             2014-01-31
10190                      2014-02-01             2014-09-30

要求输出:

 10190 | 2014-01-01 | 2014-01-31 | 2014-02-01 | 2014-09-30

有一种方法可以使用 FOR XML 运算符将日期值连接到一个列中:

DECLARE @tb AS TABLE
(
    InsuredMemberIdentifier INT
    ,CoverageStartDate DATE
    ,CoverageEndDate DATE
)

INSERT INTO @tb VALUES (10190, '2014-01-01', '2014-01-31');
INSERT INTO @tb VALUES (10190, '2014-02-01', '2014-09-30');
INSERT INTO @tb VALUES (10191, '2014-02-01', '2014-09-30');

SELECT DISTINCT InsuredMemberIdentifier
    ,ISNULL(STUFF(
        (SELECT ' ' + CAST(CoverageStartDate  AS NVARCHAR(15)) + ' ' + CAST(CoverageEndDate  AS NVARCHAR(15))
         FROM @tb tb_inner
         WHERE tb_inner.InsuredMemberIdentifier = tb.InsuredMemberIdentifier 
         FOR XML PATH (''))
         ,1,1,''), '') AS ConcatenatedDates
FROM @tb tb
WHERE InsuredMemberIdentifier = 10190

看看 SQL 透视和逆透视

https://technet.microsoft.com/en-us/library/ms177410%28v=sql.105%29.aspx

样本TABLE

CREATE TABLE #EdgeServer_EligibilityConsolidated_Part3 (InsuredMemberIdentifier INT, CoverageStartDate DATE,   CoverageEndDate DATE)

INSERT INTO #EdgeServer_EligibilityConsolidated_Part3
SELECT 10190 ,                     '2014-01-01',             '2014-01-31'
UNION ALL
SELECT 10190,                      '2014-02-01',             '2014-09-30'

第 1 步

1.Since你需要根据两列值将行转换为列(Pivot),你需要先将两列中的值转换为单列(称为Unpivot).
2.Since 您是 pivot 的新手,我正在创建一个临时的 table 来保存值,以便于您理解。 所以查询将如下

SELECT  ROW_NUMBER() OVER(ORDER BY DATES) COLUMNHEADERS,
InsuredMemberIdentifier,DATES
INTO #TEMP
FROM   #EdgeServer_EligibilityConsolidated_Part3
CROSS apply (VALUES (CoverageStartDate),
                   (CoverageEndDate)) cs (DATES)
WHERE InsuredMemberIdentifier = 10190

CROSS APPLY

相同
SELECT InsuredMemberIdentifier,CoverageStartDate
FROM #EdgeServer_EligibilityConsolidated_Part3
WHERE InsuredMemberIdentifier = 10190

UNION ALL

SELECT InsuredMemberIdentifier,CoverageEndDate
FROM #EdgeServer_EligibilityConsolidated_Part3
WHERE InsuredMemberIdentifier = 10190

所以不要混淆。

第 2 步

此变量中的值将是要作为 pivot

的一部分生成的 table 的列名
DECLARE @cols NVARCHAR (MAX)

SELECT @cols = COALESCE (@cols + ',[' + CAST(COLUMNHEADERS AS VARCHAR(50)) + ']', 
                '[' + CAST(COLUMNHEADERS AS VARCHAR(50)) + ']')
               FROM (SELECT COLUMNHEADERS FROM #TEMP) PV 
               ORDER BY COLUMNHEADERS

第 3 步

由于您无法预测日期值的数量或硬编码日期值(因为列数是动态的,不能用逗号来写),您需要使用 Dynamic Sql

DECLARE @query NVARCHAR(MAX)

SET @query = '--This is the query result - InsuredMemberIdentifier and columns with dates
             SELECT InsuredMemberIdentifier,' + @cols + ' FROM 
             (
                 -- Here you will select the columns before pivoting. COLUMNHEADERS will be name of column
                 -- and each date will be displayed under that column 
                 SELECT COLUMNHEADERS,InsuredMemberIdentifier,DATES
                 FROM #TEMP
             ) x
             PIVOT 
             (
                 -- Tells what should be the values in each column(ie, values in 2014-01-01,2014-01-31 etc)
                 MIN(DATES)
                 -- You will tell SQL to show values in @cols to be the column names
                 -- by taking corresponding DATES from its corresponding COLUMNHEADERS
                 FOR [COLUMNHEADERS] IN (' + @cols + ')
            ) p
            ' 

EXEC SP_EXECUTESQL @query

当您输入 PRINT @QUERY 而不是 EXEC SP_EXECUTESQL @query 时,它会显示以下结果

请参阅,SQL 服务器为您动态生成列名称 1,2,3,4,因为您正在使用 Dynamic Sql。当只有两个日期时,只会生成列名1,2

最终结果

select a.InsuredMemberIdentifier,a.CoverageStartDate,a.CoverageEndDate,b.CoverageStartDate,b.CoverageEndDate 来自 (select top 1 *,ROW_NUMBER() over(partition by InsuredMemberIdentifier order by (select 0)) as r from APCD.DBO.EdgeServer_EligibilityConsolidated_Part3 order by r )一种 , (select top 1 *,ROW_NUMBER() over(partition by InsuredMemberIdentifier order by (select 0)) as r from APCD.DBO.EdgeServer_EligibilityConsolidated_Part3 order by r描述) b