使用案例条件将多列转换为行
Posted
技术标签:
【中文标题】使用案例条件将多列转换为行【英文标题】:Transpose multiple column into rows using case condition 【发布时间】:2018-09-10 13:32:02 【问题描述】:我在下面有一个 SQL 查询
select
row_number()
OVER (ORDER BY hapf.position_code) Identifier,
hapf.position_code as position_code,
pg.name as gradename,
pgsfv.name as stepname
from
hr_all_positions_f hapf, PER_VALID_GRADES_F pvgf, per_grades pg, PER_GRADE_STEPS_F_VL pgsfv
where
hapf.position_id = pvgf.position_id
and pvgf.grade_id = pg.grade_id
and pgsfv.grade_id = pg.grade_id
and hapf.position_code = 'PRGUSPOS084'
and TO_CHAR(hapf.effective_end_date, 'YYYY-MM-DD') = '4712-12-31'
输出如下
Identifier Position_Code Gradename Stepname
1 PRGUSPOS084 Salary05 Step01
2 PRGUSPOS084 Salary05 Step02
3 PRGUSPOS084 Salary05 Step03
4 PRGUSPOS084 Salary06 Step01
5 PRGUSPOS084 Salary06 Step02
6 PRGUSPOS084 Salary06 Step03
7 PRGUSPOS084 Salary07 Step01
8 PRGUSPOS084 Salary07 Step02
9 PRGUSPOS084 Salary07 Step03
我已经使用 case when condition 将 GradeName 列转换为如下所示的行
SQL
select
row_number()
OVER (ORDER BY position_code) RN,
position_code as pos,
--stepname as step,
max(case when Identifier = 1 then gradename end) as Grade1,
max(case when Identifier = 2 then gradename end) as Grade2,
max(case when Identifier = 3 then gradename end) as Grade3
from
(
select
row_number()
OVER (ORDER BY hapf.position_code) Identifier,
hapf.position_code as position_code,
pg.name as gradename,
pgsfv.name as stepname
from
hr_all_positions_f hapf, PER_VALID_GRADES_F pvgf, per_grades pg, PER_GRADE_STEPS_F_VL pgsfv
where
hapf.position_id = pvgf.position_id
and pvgf.grade_id = pg.grade_id
and pgsfv.grade_id = pg.grade_id
and hapf.position_code = 'PRGUSPOS084'
and TO_CHAR(hapf.effective_end_date, 'YYYY-MM-DD') = '4712-12-31'
) x
group by position_code
此查询的输出如下
RN POS GRADE1 GRADE2 GRADE3
1 PRGUSPOS084 Salary 05 Salary 06 Salary 07
但我想要如下输出
NO POS GRADE1 GRADE2 GRADE3 Grade1Step1 Grade1Step2 Grade1Step3 Grade2Step1 Grade2Step2 Grade2Step3 Grade3Step1 Grade3Step2 Grade3Step3
1 PRGUSPOS084 Salary 05 Salary 06 Salary 07 Step01 Step02 Step03 Step01 Step02 Step03 Step01 Step02 Step03
怎么可能使用另一个case语句?
我尝试了以下但输出不正确,请帮助。
select
pos,
Grade1,
Grade2,
Grade3,
max(case when RN = 1 then step end) as stepname1,
max(case when RN = 2 then step end) as stepname2,
max(case when RN = 3 then step end) as stepname3
from
(
select
row_number()
OVER (ORDER BY position_code) RN,
position_code as pos,
stepname as step,
max(case when Identifier = 1 then gradename end) as Grade1,
max(case when Identifier = 2 then gradename end) as Grade2,
max(case when Identifier = 3 then gradename end) as Grade3
from
(
select
row_number()
OVER (ORDER BY hapf.position_code) Identifier,
hapf.position_code as position_code,
pg.name as gradename,
pgsfv.name as stepname
from
hr_all_positions_f hapf, PER_VALID_GRADES_F pvgf, per_grades pg, PER_GRADE_STEPS_F_VL pgsfv
where
hapf.position_id = pvgf.position_id
and pvgf.grade_id = pg.grade_id
and pgsfv.grade_id = pg.grade_id
and hapf.position_code = 'PRGUSPOS084'
and TO_CHAR(hapf.effective_end_date, 'YYYY-MM-DD') = '4712-12-31'
) x
group by position_code
, stepname
) z group by pos, Grade1, Grade2, Grade3
【问题讨论】:
您的第一个查询将获得所有三个年级职位的Salary05
。您是否总是期望每个职位准确或至少最多三个等级,每个职位/等级三个步骤? (输出中的第 9 行应该是 Salary07
,而不是 Salary05
?)
感谢您的回复,stepname 列中的值仅供参考,我不能放最大条款。关于 stepname 附加了其他值,因此需要在一行中为特定的等级名称提取特定的 stepname。你说得对,第 9 行有错字,我会改正的。
【参考方案1】:
您可以在内部查询中调用多个分析函数,使用不同的partition-by clauses,而不仅仅是一个;然后从这些开始 - 结合案例表达式中的等级和步骤的分析排名。
由于我没有您的基表,因此我已将您示例中的固定值作为进一步的内部查询来演示该想法,并使用一个额外的值来显示第二行输出:
select position_num,
position_code,
max(case when grade_num = 1 then grade_name end) as grade1,
max(case when grade_num = 2 then grade_name end) as grade2,
max(case when grade_num = 3 then grade_name end) as grade3,
max(case when grade_num = 1 and grade_step_num = 1 then step_name end) as Grade1Step1,
max(case when grade_num = 1 and grade_step_num = 2 then step_name end) as Grade1Step2,
max(case when grade_num = 1 and grade_step_num = 3 then step_name end) as Grade1Step3,
max(case when grade_num = 2 and grade_step_num = 1 then step_name end) as Grade2Step1,
max(case when grade_num = 2 and grade_step_num = 2 then step_name end) as Grade2Step2,
max(case when grade_num = 2 and grade_step_num = 3 then step_name end) as Grade2Step3,
max(case when grade_num = 3 and grade_step_num = 1 then step_name end) as Grade3Step1,
max(case when grade_num = 3 and grade_step_num = 2 then step_name end) as Grade3Step2,
max(case when grade_num = 3 and grade_step_num = 3 then step_name end) as Grade3Step3
from (
select
dense_rank() over (order by position_code) position_num,
position_code,
grade_name,
step_name,
dense_rank() over (partition by position_code order by grade_name) as grade_num,
dense_rank() over (partition by position_code, grade_name order by step_name) as grade_step_num
from
(
select 'PRGUSPOS084' as position_code, 'Salary05' as grade_name, 'Step01' as step_name from dual
union all select 'PRGUSPOS084', 'Salary05', 'Step02' from dual
union all select 'PRGUSPOS084', 'Salary05', 'Step03' from dual
union all select 'PRGUSPOS084', 'Salary06', 'Step01' from dual
union all select 'PRGUSPOS084', 'Salary06', 'Step02' from dual
union all select 'PRGUSPOS084', 'Salary06', 'Step03' from dual
union all select 'PRGUSPOS084', 'Salary07', 'Step01' from dual
union all select 'PRGUSPOS084', 'Salary07', 'Step02' from dual
union all select 'PRGUSPOS084', 'Salary07', 'Step03' from dual
union all select 'PRGUSPOS085', 'Salary06', 'Step02' from dual
)
)
group by position_num, position_code;
得到:
POSITION_NUM POSITION_CO GRADE1 GRADE2 GRADE3 GRADE1 GRADE1 GRADE1 GRADE2 GRADE2 GRADE2 GRADE3 GRADE3 GRADE3
------------ ----------- -------- -------- -------- ------ ------ ------ ------ ------ ------ ------ ------ ------
1 PRGUSPOS084 Salary05 Salary06 Salary07 Step01 Step02 Step03 Step01 Step02 Step03 Step01 Step02 Step03
2 PRGUSPOS085 Salary06 Step02
所以你真正的查询可能会是这样的:
select position_num,
position_code,
max(case when grade_num = 1 then grade_name end) as grade1,
max(case when grade_num = 2 then grade_name end) as grade2,
max(case when grade_num = 3 then grade_name end) as grade3,
max(case when grade_num = 1 and grade_step_num = 1 then step_name end) as Grade1Step1,
max(case when grade_num = 1 and grade_step_num = 2 then step_name end) as Grade1Step2,
max(case when grade_num = 1 and grade_step_num = 3 then step_name end) as Grade1Step3,
max(case when grade_num = 2 and grade_step_num = 1 then step_name end) as Grade2Step1,
max(case when grade_num = 2 and grade_step_num = 2 then step_name end) as Grade2Step2,
max(case when grade_num = 2 and grade_step_num = 3 then step_name end) as Grade2Step3,
max(case when grade_num = 3 and grade_step_num = 1 then step_name end) as Grade3Step1,
max(case when grade_num = 3 and grade_step_num = 2 then step_name end) as Grade3Step2,
max(case when grade_num = 3 and grade_step_num = 3 then step_name end) as Grade3Step3
from (
select
dense_rank() over (order by hapf.position_code) position_num,
hapf.position_code,
pg.name as grade_name,
pgsfv.name as step_name,
dense_rank() over (partition by hapf.position_code order by pg.name) as grade_num,
dense_rank() over (partition by hapf.position_code, pg.name order by pgsfv.name)
as grade_step_num
from
hr_all_positions_f hapf
join per_valid_grades_f pvgf on hapf.position_id = pvgf.position_id
join per_grades pg on pvgf.grade_id = pg.grade_id
join per_grade_steps_f_vl pgsfv on pgsfv.grade_id = pg.grade_id
where hapf.position_code = 'PRGUSPOS084'
and hapf.effective_end_date = date '4712-12-31'
)
group by position_num, position_code;
我冒昧地将您的内部查询转换为使用现代连接语法;并将您的 effective_end_date
与实际日期进行比较,而不是将其转换为字符串 - 这通常是一个坏主意,因为它会阻止使用该列上的索引。
【讨论】:
你是个了不起的人!非常感谢。它工作得如此顺利..再次感谢以上是关于使用案例条件将多列转换为行的主要内容,如果未能解决你的问题,请参考以下文章