使用 SQL SMS,如何将多行合并为一行,但保留所有列数据?
Using SQL SMS, how do I combine multiple rows into one row, but maintain all the column data?
我正在处理的数据目前采用以下形式:
ID Sex Treatment FillDate
1 M ziprosidone 10/01/98
1 M ziprosidone 10/15/98
1 M ziprosidone 10/29/98
1 M ambien 01/07/99
1 M ambien 01/14/99
2 F telaprevir 03/08/92
2 F telaprevir 03/20/92
2 F telaprevir 04/01/92
并且我想编写 SQL 代码来获取以下形式的数据:
ID Sex DrugFill1 FillDate1_1 FillDate1_2 FillDate1_3 DrugFill2 FillDate2_1 FillDate2_2 FillDate2_3
1 M ziprosidone 10/01/98 10/15/98 10/29/98 ambien 01/07/99 01/14/99 null
2 F telaprevir 03/08/92 03/20/92 04/01/92 null null null null
另外我想指出,我有超过 10,000 个 ID,每个 ID 都有不同数量的药物和相应的填充日期。我想 return 那些没有数据要填写的列的空值。提前致谢。
这个解决方案非常接近您的需要。如果您需要进一步的帮助来将药物排成一排 "side by side",请告诉我。实际上我不会这样做...将其粘贴到空查询 window 中并执行。适应您的需求...
编辑:将其更改为您的新药名称。
DECLARE @tbl TABLE(ID INT,Sex VARCHAR(1),Treatment VARCHAR(30),FillDate DATETIME);
INSERT INTO @tbl VALUES
(1,'M','ziprosidone',{ts'1998-01-01 00:00:00'})
,(1,'M','ziprosidone',{ts'1998-10-15 00:00:00'})
,(1,'M','ziprosidone',{ts'1998-10-29 00:00:00'})
,(1,'M','ambien',{ts'1999-01-07 00:00:00'})
,(1,'M','ambien',{ts'1999-01-14 00:00:00'})
,(2,'F','telaprevir',{ts'1992-03-08 00:00:00'})
,(2,'F','telaprevir',{ts'1992-03-02 00:00:00'})
,(2,'F','telaprevir',{ts'1992-04-01 00:00:00'});
WITH DistinctIDs AS
(
SELECT DISTINCT ID,Sex FROM @tbl
)
,DistinctDrugs AS
(
SELECT DISTINCT DistinctIDs.ID
,DistinctIDs.Sex
,tbl.Treatment
,'Drug_' + CAST(ROW_NUMBER() OVER(PARTITION BY tbl.ID,tbl.Treatment ORDER BY tbl.Treatment) AS VARCHAR(100)) AS PivotColumnName
FROM DistinctIDs
INNER JOIN @tbl AS tbl ON DistinctIDs.ID=tbl.ID
)
SELECT p.ID
,p.Sex
,p.Treatment
,CAST(p.Drug_1 AS XML).value('/root[1]/item[1]/FillDate[1]','datetime') AS Date_1
,CAST(p.Drug_1 AS XML).value('/root[1]/item[2]/FillDate[1]','datetime') AS Date_2
,CAST(p.Drug_1 AS XML).value('/root[1]/item[3]/FillDate[1]','datetime') AS Date_3
FROM
(
SELECT DistinctDrugs.*
,SubRows.XMLContent
FROM DistinctDrugs
CROSS APPLY
(
SELECT tbl.FillDate
FROM @tbl AS tbl
WHERE tbl.ID=DistinctDrugs.ID AND tbl.Treatment=DistinctDrugs.Treatment
FOR XML PATH('item'),ROOT('root')
) AS SubRows(XMLContent)
) AS DataToPivot
PIVOT
(
MIN(XMLContent) FOR PivotColumnName IN(Drug_1,Drug_2,Drug_3 /*as many as needed*/)
) AS p
我正在处理的数据目前采用以下形式:
ID Sex Treatment FillDate
1 M ziprosidone 10/01/98
1 M ziprosidone 10/15/98
1 M ziprosidone 10/29/98
1 M ambien 01/07/99
1 M ambien 01/14/99
2 F telaprevir 03/08/92
2 F telaprevir 03/20/92
2 F telaprevir 04/01/92
并且我想编写 SQL 代码来获取以下形式的数据:
ID Sex DrugFill1 FillDate1_1 FillDate1_2 FillDate1_3 DrugFill2 FillDate2_1 FillDate2_2 FillDate2_3
1 M ziprosidone 10/01/98 10/15/98 10/29/98 ambien 01/07/99 01/14/99 null
2 F telaprevir 03/08/92 03/20/92 04/01/92 null null null null
另外我想指出,我有超过 10,000 个 ID,每个 ID 都有不同数量的药物和相应的填充日期。我想 return 那些没有数据要填写的列的空值。提前致谢。
这个解决方案非常接近您的需要。如果您需要进一步的帮助来将药物排成一排 "side by side",请告诉我。实际上我不会这样做...将其粘贴到空查询 window 中并执行。适应您的需求...
编辑:将其更改为您的新药名称。
DECLARE @tbl TABLE(ID INT,Sex VARCHAR(1),Treatment VARCHAR(30),FillDate DATETIME);
INSERT INTO @tbl VALUES
(1,'M','ziprosidone',{ts'1998-01-01 00:00:00'})
,(1,'M','ziprosidone',{ts'1998-10-15 00:00:00'})
,(1,'M','ziprosidone',{ts'1998-10-29 00:00:00'})
,(1,'M','ambien',{ts'1999-01-07 00:00:00'})
,(1,'M','ambien',{ts'1999-01-14 00:00:00'})
,(2,'F','telaprevir',{ts'1992-03-08 00:00:00'})
,(2,'F','telaprevir',{ts'1992-03-02 00:00:00'})
,(2,'F','telaprevir',{ts'1992-04-01 00:00:00'});
WITH DistinctIDs AS
(
SELECT DISTINCT ID,Sex FROM @tbl
)
,DistinctDrugs AS
(
SELECT DISTINCT DistinctIDs.ID
,DistinctIDs.Sex
,tbl.Treatment
,'Drug_' + CAST(ROW_NUMBER() OVER(PARTITION BY tbl.ID,tbl.Treatment ORDER BY tbl.Treatment) AS VARCHAR(100)) AS PivotColumnName
FROM DistinctIDs
INNER JOIN @tbl AS tbl ON DistinctIDs.ID=tbl.ID
)
SELECT p.ID
,p.Sex
,p.Treatment
,CAST(p.Drug_1 AS XML).value('/root[1]/item[1]/FillDate[1]','datetime') AS Date_1
,CAST(p.Drug_1 AS XML).value('/root[1]/item[2]/FillDate[1]','datetime') AS Date_2
,CAST(p.Drug_1 AS XML).value('/root[1]/item[3]/FillDate[1]','datetime') AS Date_3
FROM
(
SELECT DistinctDrugs.*
,SubRows.XMLContent
FROM DistinctDrugs
CROSS APPLY
(
SELECT tbl.FillDate
FROM @tbl AS tbl
WHERE tbl.ID=DistinctDrugs.ID AND tbl.Treatment=DistinctDrugs.Treatment
FOR XML PATH('item'),ROOT('root')
) AS SubRows(XMLContent)
) AS DataToPivot
PIVOT
(
MIN(XMLContent) FOR PivotColumnName IN(Drug_1,Drug_2,Drug_3 /*as many as needed*/)
) AS p