如何在SQL中将包含ID、Vaccine、Date的长表转换为宽表?
将长格式疫苗接种数据转置为宽格式的SQL解决方案
我有一个包含ID、Vaccine、Date字段的数据集,同一ID对应同一种疫苗可能有1到3个接种日期记录,当前存储为每行一个日期的长格式数据:
| ID | Vaccine | Date |
|---|---|---|
| A | Flu | 1/15/2005 |
| A | Flu | 3/25/2005 |
| B | Flu | 1/15/2005 |
| B | TB | 1/15/2005 |
| B | TB | 2/15/2005 |
| B | TB | 3/15/2005 |
| B | Flu | 4/18/2005 |
| C | Flu | 1/15/2005 |
| C | TB | 5/21/2005 |
需要将其转换为以下宽格式表,每个ID+疫苗组合占一行,接种日期分别放到Date1、Date2、Date3列:
| ID | Vaccine | Date1 | Date2 | Date3 |
|---|---|---|---|---|
| A | Flu | 1/15/2005 | 3/25/2005 | |
| B | Flu | 1/15/2005 | 4/18/2005 | |
| B | TB | 1/15/2005 | 2/15/2005 | 3/15/2005 |
| C | Flu | 1/15/2005 | ||
| C | TB | 5/21/2005 |
解决方案
方法1:条件聚合(兼容绝大多数数据库)
这种写法适配MySQL、PostgreSQL、SQL Server、Oracle等主流数据库,兼容性最强:
SELECT ID, Vaccine, MAX(CASE WHEN rn = 1 THEN Date END) AS Date1, MAX(CASE WHEN rn = 2 THEN Date END) AS Date2, MAX(CASE WHEN rn = 3 THEN Date END) AS Date3 FROM ( -- 给每个ID+疫苗组合内的日期排序,生成序号 SELECT ID, Vaccine, Date, ROW_NUMBER() OVER (PARTITION BY ID, Vaccine ORDER BY Date) AS rn FROM your_table_name -- 替换为你的实际表名 ) t GROUP BY ID, Vaccine ORDER BY ID, Vaccine;
方法2:PIVOT语法(适用于SQL Server、Oracle等支持PIVOT的数据库)
如果你的数据库支持PIVOT,可以用更简洁的语法:
SELECT * FROM ( SELECT ID, Vaccine, Date, -- 生成Date1、Date2、Date3列名 'Date' + CAST(ROW_NUMBER() OVER (PARTITION BY ID, Vaccine ORDER BY Date) AS VARCHAR(10)) AS DateCol FROM your_table_name -- 替换为你的实际表名 ) t PIVOT ( MAX(Date) FOR DateCol IN ([Date1], [Date2], [Date3]) ) p ORDER BY ID, Vaccine;
内容的提问来源于stack exchange,提问作者user12501522
相关产品推荐
相关产品推荐

