将行数据转换为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
。
- Click here 查看结果
最终结果
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
在下面的情况下,我有 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
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
。
- Click here 查看结果
最终结果
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