【ピンデュオインタビューの質問】
2つのバスケットボールチームが激しく競り合い、得点が交互に上がりました。試合後、2 つのチームのスコアの内訳が表示されます。
テーブルには、チーム、選手番号、選手名、得点、得点が記録された日時が記録されます。今、チームはゲームで傑出した選手に報いる必要があります。
質問:
チームのために連続して 3 回 (またはそれ以上) 得点したプレーヤーのリストをカウントする SQL ステートメントを記述してください。
【問題解決手順】
1.窓関数
チームのために連続して 3 回 (およびそれ以上) 得点を挙げたプレーヤーのリスト. この文章を母国語で訳すと: Find the player [name] in [each team] who has three times for the team (そして上)連続。
「それぞれ」については、「Monkeys Learn SQL from Zero」で述べたように、グループ化またはウィンドウ関数を使用することを考えてください。
問題が「連続問題」であるため、連続して 3 回以上得点するということは、得点時間によってゲームが前から後ろにソートされることを意味します。したがって、ウィンドウ関数を使用して、最初にチームでグループ化し、次に得点時間で並べ替えます。
たとえば、下の図でチームごとにグループ化し、得点時間の多い順に並べ替えた後、チーム A のプレーヤー A1 とチーム B のプレーヤー B3 の名前が 3 回連続して表示されることがわかります。
対応するウィンドウ関数は次のとおりです。
select *,
rank() over(partition by 球队
order by 得分时间) as 排名
from 分数表;
検索結果:
上記の結果では、A1 が 3 回連続して表示されていることが肉眼で確認できますが、SQL ステートメントを使用して 3 回連続して表示されるすべてのプレーヤー名を取得するにはどうすればよいでしょうか。
2. 3 回連続して現れる値を見つけます
最初の列「プレーヤー名」を 1 行上に移動して 2 列目に、2 行上に移動して 3 列目に移動すると、1 列目の元の 3 つの連続した値が同じ行に移動します。たとえば、下の図では、列 1 の 3 つの連続する A1 値が同じ行に配置されています。
この変更の後、3 つの列の値が等しくなるように制限する where 句のみが必要になり、3 回連続して表示されるプレーヤーの名前を除外できます。
では、SQL を使用して上記の 2 つの列の転位の効果を達成するにはどうすればよいでしょうか。
ウィンドウ関数のラグまたはリードを使用できます。
上向きの窓関数リード: フィールド名が配置されている列と、上にN 行のデータを取り出し、独立した列として
下向きウィンドウ関数ラグ: フィールド名が配置されている列を取り出し、独立した列として下のN 行のデータ
ウィンドウ関数の構文は次のとおりです。
lag(フィールド名, N, デフォルト値) over(partion by ... order by ...)
Lead(フィールド名, N, デフォルト値) over(partition by ... order by ...)
デフォルト値は、値が N 行上または N 行下に移動したときに、テーブルの行と列の範囲を超えた場合、このデフォルト値が関数の戻り値として使用されることを意味します。デフォルト値が指定されていない場合は、 null が返されます。
これはまだ抽象的すぎるため、理解するために例を見てみましょう。
下の図は、A1 から 1 行上が表の行と列の範囲を超えているため、上向きのウィンドウ関数を使用して 1 行上のプレーヤーの名前の列 (2 列目) を取得するため、ここでの対応する値は次のようになります。デフォルト値 (デフォルト値が設定されていない場合は null )。
対応する SQL ステートメント:
select 球员姓名,
lead(球员姓名,1) over(partition by 球队
order by 得分时间) as 下一项
from 分数表;
下の図は、下向きのウィンドウ関数ラグを使用して、プレーヤーの名前の列 (2 列目) を 1 行下に取得し、
対応する SQL ステートメントは次のとおりです。
select 球员姓名,
lag(球员姓名,1) over(partition by 球队
order by 得分时间) as 上一行
from 分数表;
前の分析によると、プレーヤーの名前の値を 1 行上と 2 行上に取得する必要があります。つまり、次のようになります。
リード(プレイヤー名,1)
リード(プレイヤー名, 2)
対応する SQL は次のとおりです。
select 球员姓名,
lead(球员姓名,1) over(partition by 球队 order by 得分时间) as 姓名1,
lead(球员姓名,2) over(partition by 球队 order by 得分时间) as 姓名2
from 分数表;
検索結果:
3. SQL 実行シーケンス
上記の作業が完了したら、where 句を使用して、同じ 3 つの値 (プレーヤー名 = 名前 1 とプレーヤー名 = 名前 2) を持つ行を除外できます。
ただし、前述のSQL 実行シーケンスによると、上記の手順の直後に where 句を追加できないことに注意してください。SQL の実行順序によると、from 句と where 句が最初に実行され、次に select 句が実行されるためです。
そのため、name 1 と name 2 の 2 つの列は select の最後の実行まで表示されず、サブクエリを使用して解決する必要があり、同時に、最後のプレーヤー名を重複排除 (disitinct) する必要があります。
select distinct 球员姓名
from(
select 球员姓名,
lead(球员姓名,1) over(partition by 球队 order by 得分时间) as 姓名1,
lead(球员姓名,2) over(partition by 球队 order by 得分时间) as 姓名2
from 分数表
) as a
where (a.球员姓名 = a.姓名1 and a.球员姓名 = a.姓名2);
検索結果:
この場合、ウィンドウ関数ラグも使用でき、同じ結果が得られます.原理は似ています.自分で絵を描いて私に送って、練習後に学習結果を共有することができます.
【本問のテストポイント】
1. SQL の実行順序とサブクエリを調べる
2. ウィンドウ関数で使用できる問題は何ですか?
「Monkey Learned SQL from Zero」では、次のビジネス シナリオではウィンドウ関数を使用する必要があると述べています。
3. 窓関数のラグとリードの使い方を調べる
これら 2 つの関数は、通常、差を計算するために使用されます。次に例を示します。
1) 計算に時間がかかる。たとえば、特定のデータは、各ユーザーが Web ページを閲覧した時間の記録であり、記録された時間が失われた後、各ユーザーが各 Web ページを閲覧した実際の時間は、2 つの列を減算することによって取得できます。
2) 前回と比較した昇給額を計算します。
【類推で学ぶ】
将来、この種の問題が N 回連続して発生する場合は、次のユニバーサル テンプレートを使用して解決できます。
select distinct 列1
from(
select 列1,
lead(列1,1) over(order by 序号) as 列2,
lead(列1,2) over(order by 序号) as 列3,
...
lead(列1,n-1) over(order by 列) as 列n,
from 表名
) as a
where (a.列1 = a.列2 and ... and a.列1 = a.列n);
例:
以下は学生の成績表 (テーブル名は点数、列名は学生番号、成績) です。SQL を使用して、少なくとも 3 回連続して現れるすべての成績を検索します。
この質問では、ラグ関数を使用します。
対応する SQL の実装は次のとおりです。
select 成绩,
lag(成绩,1) over(order by 学号) as 成绩1,
lag(成绩,2) over(order by 学号) as 成绩2
from 成绩表;
検索結果:
最終的な答え:
select distinct 成绩
from(
select 成绩,
lag(成绩,1) over(order by 学号) as 成绩1,
lag(成绩,2) over(order by 学号) as 成绩2
from 成绩表)t
where (t.成绩 = t.成绩1 and t.成绩 = t.成绩2);
検索結果:
⬇️「原文を読む」をクリック
無料データ分析トレーニングキャンプに申し込む