SQL 服务器 - 有条件地转置数据
SQL Server - transpose data conditionally
我有如下图所示的数据集:
Original dataset
我需要构建如下报告:
Report needed
基本上每个人在 PersonLang 中都有一些条目 table。这些条目代表每个语言技能组合加上级别的一行。
该报告应包含一个人知道的所有语言,按分数(级别)的降序排列。先高级后中等
到目前为止我已经尝试了一些事情:
- 我尝试使用 PIVOT,但我事先不知道一个人的所有语言,而且如果一个人只知道一种语言,它应该出现在第一列中
- 我尝试使用按 personid 分区并按语言级别排序的 window 函数 (Lead)。在这里我遇到了问题,因为我需要每种语言的所有技能一行
- 我正在考虑编写一个 table 值函数,它将原始数据集作为游标,然后将其转换为所需的 table。在这里,我在同一行中插入所有值时遇到问题,如果语言在同一级别出现两次,我应该只更新级别。
我想我想多了,也许头脑更清醒的人可以指出正确的解决方案。应该对原始数据集应用什么才能获得所需的结果?
SQL 语句复制数据:
create table personlang(
personid number,
lang varchar2(20),
langskill varchar2(20),
lvl varchar2(20),
score number)
insert into personlang values (101, 'Dutch', 'Spoken', 'Advanced', 3);
insert into personlang values (101, 'Dutch', 'Written', 'Medium', 2);
insert into personlang values (101, 'French', 'Spoken', 'Medium', 2);
insert into personlang values (101, 'Arabic', 'Written','Begineer',1);
insert into personlang values (102, 'English', 'Spoken','Advanced',3);
提前致谢
DECLARE @sql NVARCHAR(max),@col NVARCHAR(max)
SELECT @col=ISNULL(@col+',','')+'[ForeignLand'+n.LangID+'],[ForeignLand'+n.LangID+'Spoken],['+'ForeignLand'+n.LangID+'Written]'
FROM (
SELECT DISTINCT CONVERT(VARCHAR,DENSE_RANK()OVER(PARTITION BY personid ORDER BY lang)) AS LangID
FROM personlang
) n
PRINT @col
SELECT @sql='
SELECT * FROM (
SELECT l.personid,c.* FROM (
SELECT *, DENSE_RANK()OVER(PARTITION BY pl.personid ORDER BY lang) AS LangID FROM personlang AS pl
) l
CROSS APPLY (VALUES(''ForeignLand''+CONVERT(VARCHAR,LangID),lang)
,(''ForeignLand''+CONVERT(VARCHAR,LangID)+''Spoken'',CASE WHEN langskill=''Spoken'' THEN lvl ELSE NULL END )
,(''ForeignLand''+CONVERT(VARCHAR,LangID)+''Written'',CASE WHEN langskill=''Written'' THEN lvl ELSE NULL END )
) c(col_title,col_value)
)m
PIVOT(MAX(m.col_value) FOR m.col_title IN('+@col+')) p'
exec(@sql)
personid ForeignLand1 ForeignLand1Spoken ForeignLand1Written ForeignLand2 ForeignLand2Spoken ForeignLand2Written ForeignLand3 ForeignLand3Spoken ForeignLand3Written
----------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- --------------------
101 Arabic NULL Begineer Dutch Advanced Medium French Medium NULL
102 English Advanced NULL NULL NULL NULL NULL NULL NULL
我有如下图所示的数据集: Original dataset
我需要构建如下报告: Report needed
基本上每个人在 PersonLang 中都有一些条目 table。这些条目代表每个语言技能组合加上级别的一行。
该报告应包含一个人知道的所有语言,按分数(级别)的降序排列。先高级后中等
到目前为止我已经尝试了一些事情:
- 我尝试使用 PIVOT,但我事先不知道一个人的所有语言,而且如果一个人只知道一种语言,它应该出现在第一列中
- 我尝试使用按 personid 分区并按语言级别排序的 window 函数 (Lead)。在这里我遇到了问题,因为我需要每种语言的所有技能一行
- 我正在考虑编写一个 table 值函数,它将原始数据集作为游标,然后将其转换为所需的 table。在这里,我在同一行中插入所有值时遇到问题,如果语言在同一级别出现两次,我应该只更新级别。
我想我想多了,也许头脑更清醒的人可以指出正确的解决方案。应该对原始数据集应用什么才能获得所需的结果?
SQL 语句复制数据:
create table personlang(
personid number,
lang varchar2(20),
langskill varchar2(20),
lvl varchar2(20),
score number)
insert into personlang values (101, 'Dutch', 'Spoken', 'Advanced', 3);
insert into personlang values (101, 'Dutch', 'Written', 'Medium', 2);
insert into personlang values (101, 'French', 'Spoken', 'Medium', 2);
insert into personlang values (101, 'Arabic', 'Written','Begineer',1);
insert into personlang values (102, 'English', 'Spoken','Advanced',3);
提前致谢
DECLARE @sql NVARCHAR(max),@col NVARCHAR(max)
SELECT @col=ISNULL(@col+',','')+'[ForeignLand'+n.LangID+'],[ForeignLand'+n.LangID+'Spoken],['+'ForeignLand'+n.LangID+'Written]'
FROM (
SELECT DISTINCT CONVERT(VARCHAR,DENSE_RANK()OVER(PARTITION BY personid ORDER BY lang)) AS LangID
FROM personlang
) n
PRINT @col
SELECT @sql='
SELECT * FROM (
SELECT l.personid,c.* FROM (
SELECT *, DENSE_RANK()OVER(PARTITION BY pl.personid ORDER BY lang) AS LangID FROM personlang AS pl
) l
CROSS APPLY (VALUES(''ForeignLand''+CONVERT(VARCHAR,LangID),lang)
,(''ForeignLand''+CONVERT(VARCHAR,LangID)+''Spoken'',CASE WHEN langskill=''Spoken'' THEN lvl ELSE NULL END )
,(''ForeignLand''+CONVERT(VARCHAR,LangID)+''Written'',CASE WHEN langskill=''Written'' THEN lvl ELSE NULL END )
) c(col_title,col_value)
)m
PIVOT(MAX(m.col_value) FOR m.col_title IN('+@col+')) p'
exec(@sql)
personid ForeignLand1 ForeignLand1Spoken ForeignLand1Written ForeignLand2 ForeignLand2Spoken ForeignLand2Written ForeignLand3 ForeignLand3Spoken ForeignLand3Written ----------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- -------------------- 101 Arabic NULL Begineer Dutch Advanced Medium French Medium NULL 102 English Advanced NULL NULL NULL NULL NULL NULL NULL