0 ニーズ
1 需要分析
要件分析: 要件では、ランキングに従ってグループ内の最後から 2 番目の値を新しいフィールドとして見つけ、グループ内に最後から 2 番目の項目がない場合は現在の値を取る必要があります。
この質問が、グループ内でソートした後、最後から 2 番目を見つけることのみである場合、それは非常に単純であり、row_number() 関数を使用してそれを見つけることができますが、この質問の問題は、現在の値が必要であるということです。最後から2番目がない場合に保持されますが、エレガントに見つける方法は?
次の結果を取得するには、row_number() 関数を使用します。
with data as
(select 111 as stu_id, 'class1' as class_name, 69 as score
union all
select 113 as stu_id, 'class1' as class_name, 74 as score
union all
select 112 as stu_id, 'class1' as class_name, 80 as score
union all
select 115 as stu_id, 'class1' as class_name, 93 as score
union all
select 114 as stu_id, 'class1' as class_name, 94 as score
union all
select 124 as stu_id, 'class2' as class_name, 70 as score
union all
select 121 as stu_id, 'class2' as class_name, 74 as score
union all
select 123 as stu_id, 'class2' as class_name, 78 as score
union all
select 122 as stu_id, 'class2' as class_name, 86 as score
union all
select 9999 as stu_id, 'class3' as class_name, 99 as score
)
select stu_id
, class_name
, score
, row_number() over (partition by class_name order by score desc ) rn1
from data
上記の結果に基づいて、最後から 2 番目の値を取り出すにはどうすればよいですか? 上位層は、rn = 2 の場合にケースを使用し、効果を確認するためにスコア end を使用します。
with data as
(select 111 as stu_id, 'class1' as class_name, 69 as score
union all
select 113 as stu_id, 'class1' as class_name, 74 as score
union all
select 112 as stu_id, 'class1' as class_name, 80 as score
union all
select 115 as stu_id, 'class1' as class_name, 93 as score
union all
select 114 as stu_id, 'class1' as class_name, 94 as score
union all
select 124 as stu_id, 'class2' as class_name, 70 as score
union all
select 121 as stu_id, 'class2' as class_name, 74 as score
union all
select 123 as stu_id, 'class2' as class_name, 78 as score
union all
select 122 as stu_id, 'class2' as class_name, 86 as score
union all
select 9999 as stu_id, 'class3' as class_name, 99 as score
)
select stu_id
, class_name
, score
, case when rn1 = 2 then score end as res
from (
select stu_id
, class_name
, score
, row_number() over (partition by class_name order by score desc ) rn1
--, row_number() over (partition by class_name order by score ) rn2
from data
) t
最後から 2 番目の値が取り出されますが、それでも要件を満たしていません。要件では、このグループで生成されるフィールドの各行がこの値のすべてである必要があります。その方法は? これはデータクリーニングの手段でもあります.グループ内の空の値をグループ内の値で埋める方法は? max() 関数のウィンドウ処理: max() over(partition by group field)の手法を使用して、同じグループ内のすべての null 値が同じフィールドに割り当てられるようにします。SQL は次のとおりです。
with data as
(select 111 as stu_id, 'class1' as class_name, 69 as score
union all
select 113 as stu_id, 'class1' as class_name, 74 as score
union all
select 112 as stu_id, 'class1' as class_name, 80 as score
union all
select 115 as stu_id, 'class1' as class_name, 93 as score
union all
select 114 as stu_id, 'class1' as class_name, 94 as score
union all
select 124 as stu_id, 'class2' as class_name, 70 as score
union all
select 121 as stu_id, 'class2' as class_name, 74 as score
union all
select 123 as stu_id, 'class2' as class_name, 78 as score
union all
select 122 as stu_id, 'class2' as class_name, 86 as score
union all
select 9999 as stu_id, 'class3' as class_name, 99 as score
)
select stu_id
, class_name
, score
, max(case when rn1 = 2 then score end ) over(partition by class_name) as res
from (
select stu_id
, class_name
, score
, row_number() over (partition by class_name order by score desc ) rn1
--, row_number() over (partition by class_name order by score ) rn2
from data
) t
結果の値がますます期待どおりになっていることがわかりますが、グループ内の 1 つの値のみを処理するにはどうすればよいでしょうか? ここでは、補助的な判断が必要です. min() =max() を使用して判断するか、percent_rank()=0 を使用して判断することができます. ここでは、min() =max() を使用して判断します.グループ内の値が一意である限り、最終的な SQL は次のようになります。
with data as
(select 111 as stu_id, 'class1' as class_name, 69 as score
union all
select 113 as stu_id, 'class1' as class_name, 74 as score
union all
select 112 as stu_id, 'class1' as class_name, 80 as score
union all
select 115 as stu_id, 'class1' as class_name, 93 as score
union all
select 114 as stu_id, 'class1' as class_name, 94 as score
union all
select 124 as stu_id, 'class2' as class_name, 70 as score
union all
select 121 as stu_id, 'class2' as class_name, 74 as score
union all
select 123 as stu_id, 'class2' as class_name, 78 as score
union all
select 122 as stu_id, 'class2' as class_name, 86 as score
union all
select 9999 as stu_id, 'class3' as class_name, 99 as score
)
select stu_id
, class_name
, score
, max(case
when rn1 != rn2 and rn1 = 2 --正序和倒序值不等 则取倒数第二的值 (rn1=2的值)
then score
when rn1 = rn2 then score --正序和倒序值相等 则取当前值
end) over (partition by class_name) res
from (
select stu_id
, class_name
, score
, dense_rank() over (partition by class_name order by score desc ) rn1
, dense_rank() over (partition by class_name order by score) rn2 --用来辅助判断
-- , percent_rank() over (partition by class_name order by score) pr --也可以采用该函数辅助判断(pr=0时候)
from data
) t
2 まとめ
この記事では、実際の需要におけるケースを通じて、グループ内の null 値を埋めるスキルを完了する方法について説明します。ウィンドウを開くことによって、min()/max() オーバー (グループ化フィールドによるパーティション) を補足し、注意を払う必要があります。実際の状況に応じた max() 関数は、case when ステートメントを書くか、実際のニーズを満たす条件を構築します.この手法は、データの明確化のためによく使用されます.