Dynamic Pivot 中的列不会在下一个关键项目处重新开始
Posted
技术标签:
【中文标题】Dynamic Pivot 中的列不会在下一个关键项目处重新开始【英文标题】:Columns in Dynamic Pivot don't start over at next key item 【发布时间】:2017-04-25 17:16:17 【问题描述】:这是已部分回答的其他问题的延续,但我认为当前状态现在已经丢失。
首先,我有一个临时表,其中存储了一些用于查询数据库的变量。从那里我建立了一个临时表来识别满足以下查询中某些条件的访问:
SELECT
spl.trac_id
,CONVERT(DATE,pev.CONTACT_DATE) AS 'Contact'
INTO
#medmtemp
FROM
#SAMHSA_PAT_LIST spl
INNER JOIN dbo.IDENTITY_ID_VIEW iiv
ON iiv.IDENTITY_ID=spl.MRN
LEFT JOIN dbo.PAT_ENC_VIEW pev
ON pev.PAT_ID = iiv.PAT_ID
LEFT JOIN dbo.PAT_ENC_RSN_VISIT_VIEW rsn
ON rsn.PAT_ENC_CSN_ID=pev.PAT_ENC_CSN_ID
WHERE
pev.CONTACT_DATE >= @Start_Date
AND pev.CONTACT_DATE < @End_Date
AND pev.APPT_STATUS_C IN ( 2 , 6 , 8 , 9 )
AND rsn.ENC_REASON_ID = 590;
从那里我创建了一个如下所示的数据透视查询:
DECLARE @SQL NVARCHAR(MAX)=''
,@PVT_COL NVARCHAR(MAX)='';
SELECT @PVT_COL =@PVT_COL + '[mm_'+CAST(ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS VARCHAR(4))+'],'
FROM #medmtemp
SELECT @PVT_COL = LEFT(@PVT_COL,LEN(@PVT_COL)-1)
SELECT @SQL =
N'SELECT * FROM (
SELECT [trac_id], Contact ,''mm_''+CAST(ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS VARCHAR(4)) AS COL_NME
FROM #medmtemp
)AS A
PIVOT
(
MAX(Contact) FOR COL_NME IN (' + @PVT_COL + ')
)PVT'
EXECUTE (@SQL)
不幸的是,我看到的结果是这样的:
trac_id mm_1 mm_2 mm_3 mm_4 mm_5 mm_6 mm_7 mm_8 mm_9 mm_10 mm_11 mm_12 mm_13 mm_14 mm_15 mm_16 mm_17 mm_18 mm_19 mm_20
001 2017-03-01 2017-03-08 2017-03-13 2017-03-16 2017-03-16 2017-03-17 2017-03-22 2017-03-23 2017-03-23 2017-03-24 2017-03-27 2017-03-27 2017-03-30 2017-03-31 NULL NULL NULL NULL NULL NULL
005 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 2017-02-16 2017-03-18 2017-03-08 NULL NULL NULL
008 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 2017-03-08 2017-03-23 2017-03-30
我希望将数据格式化为:
trac_id mm_1 mm_2 mm_3 mm_4 mm_5 mm_6 mm_7 mm_8 mm_9 mm_10 mm_11 mm_12 mm_13 mm_14
1 3/1/2017 3/8/2017 3/13/2017 3/16/2017 3/16/2017 3/17/2017 3/22/2017 3/23/2017 3/23/2017 3/24/2017 3/27/2017 3/27/2017 3/30/2017 3/31/2017
5 2/16/2017 3/18/2017 3/8/2017 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
8 3/8/2017 3/23/2017 3/30/2017 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
如果 NULL 列是空白的,那就更好了,但这更好。我希望我能解决这个问题,因为我将在多个查询中使用相同格式的 PIVOT。
【问题讨论】:
【参考方案1】:关键是在row_number()
中包含partition by trac_id
declare @cols nvarchar(max);
declare @sql nvarchar(max);
select @cols = stuff((
select distinct
',' + quotename('mm_'
+ right('0' +convert(nvarchar(10),row_number() over (
partition by trac_id
order by contact
)),2)
)
from t
for xml path (''), type).value('.','nvarchar(max)')
,1,1,'');
select @sql = '
select trac_id, ' + @cols + '
from (
select
trac_id
, contact = convert(char(10),contact,120)
, rn=''mm_''+right(''0'' +convert(nvarchar(10),row_number() over (
partition by trac_id
order by contact
)),2)
from t
) as a
pivot (max([contact]) for [rn] in (' + @cols + ') ) p';
select @sql as CodeGenerated;
exec sp_executesql @sql;
rextester 演示:http://rextester.com/XDVOTD39040
返回:
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
| CodeGenerated |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
| select trac_id, [mm_01],[mm_02],[mm_03],[mm_04],[mm_05],[mm_06],[mm_07],[mm_08],[mm_09],[mm_10],[mm_11],[mm_12],[mm_13],[mm_14] |
| from ( |
| select |
| trac_id |
| , contact = convert(char(10),contact,120) |
| , rn='mm_'+right('0' +convert(nvarchar(10),row_number() over ( |
| partition by trac_id |
| order by contact |
| )),2) |
| from t |
| ) as a |
| pivot (max([contact]) for [rn] in ([mm_01],[mm_02],[mm_03],[mm_04],[mm_05],[mm_06],[mm_07],[mm_08],[mm_09],[mm_10],[mm_11],[mm_12],[mm_13],[mm_14]) ) p |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
和
+---------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
| trac_id | mm_01 | mm_02 | mm_03 | mm_04 | mm_05 | mm_06 | mm_07 | mm_08 | mm_09 | mm_10 | mm_11 | mm_12 | mm_13 | mm_14 |
+---------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
| 001 | 2017-03-01 | 2017-03-08 | 2017-03-13 | 2017-03-16 | 2017-03-16 | 2017-03-17 | 2017-03-22 | 2017-03-23 | 2017-03-23 | 2017-03-24 | 2017-03-27 | 2017-03-27 | 2017-03-30 | 2017-03-31 |
| 005 | 2017-02-16 | 2017-03-08 | 2017-03-18 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 011 | 2017-02-16 | 2017-03-01 | 2017-03-23 | 2017-03-30 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 013 | 2017-03-08 | 2017-03-13 | 2017-03-16 | 2017-03-16 | 2017-03-17 | 2017-03-22 | 2017-03-23 | 2017-03-24 | 2017-03-27 | 2017-03-27 | 2017-03-30 | 2017-03-30 | 2017-03-31 | NULL |
| 040 | 2017-02-20 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 043 | 2017-02-03 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 059 | 2017-03-08 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 060 | 2017-02-08 | 2017-03-07 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 067 | 2017-01-24 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| 068 | 2017-02-13 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
+---------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
将null
值转换为空字符串:
declare @cols nvarchar(max);
declare @select_cols nvarchar(max);
declare @sql nvarchar(max);
select @cols = stuff((
select distinct
',' + quotename('mm_'
+ right('0' +convert(nvarchar(10),row_number() over (
partition by trac_id
order by contact
)),2)
)
from t
for xml path (''), type).value('.','nvarchar(max)')
,1,1,'');
select @select_cols = (
select distinct
char(10)+' , ' + quotename('mm_'
+ right('0' +convert(nvarchar(10),row_number() over (
partition by trac_id
order by contact
)),2)
) +' = isnull('+
quotename('mm_'
+ right('0' +convert(nvarchar(10),row_number() over (
partition by trac_id
order by contact
)),2)
)+','''')'
from t
for xml path (''), type).value('.','nvarchar(max)')
select @sql = '
select trac_id' + @select_cols + '
from (
select
trac_id
, contact = convert(char(10),contact,120)
, rn=''mm_''+right(''0'' +convert(nvarchar(10),row_number() over (
partition by trac_id
order by contact
)),2)
from t
) as a
pivot (max([contact]) for [rn] in (' + @cols + ') ) p';
select @sql as CodeGenerated;
exec sp_executesql @sql;
rextester 演示:http://rextester.com/HDTK5946
返回:
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
| CodeGenerated |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
| select trac_id |
| , [mm_01] = isnull([mm_01],'') |
| , [mm_02] = isnull([mm_02],'') |
| , [mm_03] = isnull([mm_03],'') |
| , [mm_04] = isnull([mm_04],'') |
| , [mm_05] = isnull([mm_05],'') |
| , [mm_06] = isnull([mm_06],'') |
| , [mm_07] = isnull([mm_07],'') |
| , [mm_08] = isnull([mm_08],'') |
| , [mm_09] = isnull([mm_09],'') |
| , [mm_10] = isnull([mm_10],'') |
| , [mm_11] = isnull([mm_11],'') |
| , [mm_12] = isnull([mm_12],'') |
| , [mm_13] = isnull([mm_13],'') |
| , [mm_14] = isnull([mm_14],'') |
| from ( |
| select |
| trac_id |
| , contact = convert(char(10),contact,120) |
| , rn='mm_'+right('0' +convert(nvarchar(10),row_number() over ( |
| partition by trac_id |
| order by contact |
| )),2) |
| from t |
| ) as a |
| pivot (max([contact]) for [rn] in ([mm_01],[mm_02],[mm_03],[mm_04],[mm_05],[mm_06],[mm_07],[mm_08],[mm_09],[mm_10],[mm_11],[mm_12],[mm_13],[mm_14]) ) p |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
和
+---------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
| trac_id | mm_01 | mm_02 | mm_03 | mm_04 | mm_05 | mm_06 | mm_07 | mm_08 | mm_09 | mm_10 | mm_11 | mm_12 | mm_13 | mm_14 |
+---------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
| 001 | 2017-03-01 | 2017-03-08 | 2017-03-13 | 2017-03-16 | 2017-03-16 | 2017-03-17 | 2017-03-22 | 2017-03-23 | 2017-03-23 | 2017-03-24 | 2017-03-27 | 2017-03-27 | 2017-03-30 | 2017-03-31 |
| 005 | 2017-02-16 | 2017-03-08 | 2017-03-18 | | | | | | | | | | | |
| 011 | 2017-02-16 | 2017-03-01 | 2017-03-23 | 2017-03-30 | | | | | | | | | | |
| 013 | 2017-03-08 | 2017-03-13 | 2017-03-16 | 2017-03-16 | 2017-03-17 | 2017-03-22 | 2017-03-23 | 2017-03-24 | 2017-03-27 | 2017-03-27 | 2017-03-30 | 2017-03-30 | 2017-03-31 | |
| 040 | 2017-02-20 | | | | | | | | | | | | | |
| 043 | 2017-02-03 | | | | | | | | | | | | | |
| 059 | 2017-03-08 | | | | | | | | | | | | | |
| 060 | 2017-02-08 | 2017-03-07 | | | | | | | | | | | | |
| 067 | 2017-01-24 | | | | | | | | | | | | | |
| 068 | 2017-02-13 | | | | | | | | | | | | | |
+---------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
【讨论】:
非常感谢@SqlZim。因此,将您列为“t”的内容替换为源临时表的名称会给我我所追求的。最后一个问题是,我可以将它插入到一个新的临时表中吗? @Erik 当然。您可以在动态代码select ... into ##pivoted
中使用全局临时表,例如rextester.com/EQDH71409
如果我只是将 select * 添加到 ##pivoted 中,我会收到以下错误:对象或列名丢失或为空。对于 SELECT INTO 语句,验证每一列都有一个名称。对于其他语句,请查找空别名。不允许使用定义为 "" 或 [] 的别名。将别名更改为有效名称。
@Erik 你看过演示吗?
我又看了一眼@SqlZim。我第一次看错了,把它放错了位置。现在可以了。一个快速的问题,如果我在临时表中插入数据透视结果,但稍后需要进行另一个数据透视,我不必再次声明,但可以从下面重用正确吗?以上是关于Dynamic Pivot 中的列不会在下一个关键项目处重新开始的主要内容,如果未能解决你的问题,请参考以下文章
如何将 SQL 中的列中的值 PIVOT 到新的列名中,然后在这些 PIVOT 列下列出其他列值?
将 Total 列添加到 Dynamic SQL pivot
[LeetCode] 724. Find Pivot Index_Easy tag: Dynamic Programming