SQL 競合分析 — LAG/LEAD・RANK・スコアリングの応用

応用競合他社分析LAG / LEADRANK / DENSE_RANKCASE WHEN PivotPERCENT_RANKPostgreSQL対応全5問
1 / 5 · 学習中 0 / 5 問完了
QUESTION 6

LAG() + CTE — 前期比成長率で競合の四半期トレンド加速・減速を可視化する

LAG / LEADCTE前期比成長率NULLIF・0除算防止
前提知識

LAG(expr, offset, default) はウィンドウ関数の一種で、現在行から offset 行前の値を返します。前期比・前年同期比の計算に不可欠なパターンです。

LAG(revenue) OVER (
  PARTITION BY company_name   -- 企業をまたいで前行を取らない
  ORDER BY     quarter        -- 四半期順で「1行前」を確定
)                              -- デフォルト offset=1, default=NULL
NULLIF で 0 除算を防ぐ:前期が 0 だと revenue / prev_revenue が ZeroDivisionError になります。NULLIF(prev_revenue, 0) は値が 0 のとき NULL を返すため、NULL との除算は NULL(エラーではない)として安全に処理できます。
CTE で LAG を一度だけ計算する:成長率の計算に LAG を直接 SELECT に複数回書くと保守性が下がります。CTE でまず prev_revenue を確定させ、外側クエリで再利用するのがベストプラクティスです。
問題

3社の四半期売上から、各社の前期売上(prev_revenue)と前期比成長率(growth_rate_pct、小数第1位)を算出してください。取得列は company_name, quarter, revenue, prev_revenue, growth_rate_pct、company_name 昇順 → quarter 昇順で返してください。prev_revenue と growth_rate_pct は NULL になります。

使用テーブル
▸ quarterly_revenue
company_namequarterrevenue
AlphaTech2023Q1300
AlphaTech2023Q2360
AlphaTech2023Q3280
AlphaTech2023Q4400
BetaSoft2023Q1250
BetaSoft2023Q2220
BetaSoft2023Q3290
BetaSoft2023Q4310
GammaSys2023Q1120
GammaSys2023Q2150
GammaSys2023Q3170
GammaSys2023Q4160

※ revenue 単位: 億円

期待出力
company_namequarterrevenueprev_revenuegrowth_rate_pct
AlphaTech2023Q1300NULLNULL
AlphaTech2023Q236030020.0
AlphaTech2023Q3280360-22.2
AlphaTech2023Q440028042.9
BetaSoft2023Q1250NULLNULL
BetaSoft2023Q2220250-12.0
BetaSoft2023Q329022031.8
BetaSoft2023Q43102906.9
GammaSys2023Q1120NULLNULL
GammaSys2023Q215012025.0
GammaSys2023Q317015013.3
GammaSys2023Q4160170-5.9
QUESTION 7

RANK() + CTE — カテゴリ別競合ランキングと上位 N 社フィルタ

RANK / DENSE_RANKCTE + WHEREカテゴリ別トップN同率順位の扱い
前提知識

RANK() / DENSE_RANK() / ROW_NUMBER() はいずれも順位を返すウィンドウ関数ですが、同率順位の扱いが異なります。

関数同率2位が2行ある場合次の順位
ROW_NUMBER()2, 3(擬似的に一意付与)4
RANK()2, 2(同率)4(飛び番)
DENSE_RANK()2, 2(同率)3(連番)
WITH ranked AS (
  SELECT *, RANK() OVER (PARTITION BY category ORDER BY annual_revenue DESC) AS rnk
  FROM product_revenue
)
SELECT * FROM ranked WHERE rnk <= 2;  -- 各カテゴリの上位2位以内(同率を含む)
CTE + WHERE によるトップN抽出パターン:ウィンドウ関数の結果は同一 SELECT の WHERE では参照できません(論理評価順で WHERE が先)。CTE でランクを付与し、外側の WHERE でフィルタするのが定石です。
問題

各カテゴリの競合売上データから、カテゴリ内売上ランキング(rank_in_category)を付与し、各カテゴリの上位2位以内(同率を含む)の企業のみを抽出してください。取得列は category, company_name, annual_revenue, rank_in_category、カテゴリはAI/ML→クラウド→セキュリティ→データ分析の指定順、各カテゴリ内は rank_in_category 昇順、同順位は company_name 昇順で返してください。

使用テーブル
▸ product_revenue
company_namecategoryannual_revenue
AlphaTechクラウド4200
AlphaTechセキュリティ1800
AlphaTechAI/ML950
BetaSoftクラウド2800
BetaSoftAI/ML1500
BetaSoftデータ分析800
GammaSysセキュリティ900
GammaSysAI/ML650
GammaSysデータ分析420
DeltaNetクラウド1200
DeltaNetデータ分析600

※ annual_revenue 単位: 億円

期待出力
categorycompany_nameannual_revenuerank_in_category
AI/MLBetaSoft15001
AI/MLAlphaTech9502
クラウドAlphaTech42001
クラウドBetaSoft28002
セキュリティAlphaTech18001
セキュリティGammaSys9002
データ分析BetaSoft8001
データ分析DeltaNet6002
QUESTION 8

複数 CTE スコアリング — 段階的集計で競合の総合 KPI 評価グレードを自動算出する

WITH 複数CTECASE WHEN競合スコアリング段階的集計・グレード付け
前提知識

複数の CTE は WITH 句の中にカンマで連結して定義でき、前段の CTE を後段の CTE で参照できます。複雑な集計を段階的に分解し、各ステップを名前付きで可読化できます。

WITH
step1 AS (
  SELECT ..., CASE WHEN col >= 30 THEN 3 ELSE 1 END AS score
  FROM source_table
),
step2 AS (          -- step1 を参照可能
  SELECT *, score_a + score_b AS total
  FROM step1
)
SELECT * FROM step2;
CASE WHEN の ELSE 省略に注意:CASE WHEN ... END で ELSE を省略すると ELSE NULL になります。スコアリングでは必ず ELSE 最低点 を明示してください。
問題

6社の競合 KPI データから、売上規模・成長率・NPS それぞれを 1〜3 点でスコアリングし、合計点(最大9点)と総合グレード(S/A/B/C)を算出してください。取得列は company_name, revenue_score, growth_score, nps_pts, total_score, grade、total_score 降順 → company_name 昇順で返してください。

スコア基準:revenue_score(revenue_bn ≥30→3, ≥10→2, else 1)|growth_score(growth_pct ≥25→3, ≥10→2, else 1)|nps_pts(nps_score ≥65→3, ≥50→2, else 1)|grade(total ≥8→S, ≥6→A, ≥4→B, else C)

使用テーブル
▸ competitor_kpis
company_namerevenue_bngrowth_pctnps_score
AlphaTech42.018.572
BetaSoft28.012.358
GammaSys15.031.265
DeltaNet5.08.148
EpsilonSys3.0-2.441
ZetaCloud2.05.655

※ revenue_bn: 売上(十億円)/ growth_pct: 前年成長率(%)/ nps_score: 顧客NPS

期待出力
company_namerevenue_scoregrowth_scorenps_ptstotal_scoregrade
AlphaTech3238S
GammaSys2338S
BetaSoft2226A
ZetaCloud1124B
DeltaNet1113C
EpsilonSys1113C
QUESTION 9

CASE WHEN ピボット — 縦持ち四半期売上を横持ちに変換し年内成長率を算出する

SUM + CASE WHENGROUP BY縦持ち→横持ち変換条件付き集計・NULLIF
前提知識

条件付き集計(Conditional Aggregation)は SUM(CASE WHEN ... END) パターンで縦持ち(行方向)データを横持ち(列方向)に変換します。PostgreSQL には専用の PIVOT 構文がないため、このパターンが標準的な実装です。

SELECT
  company_name,
  SUM(CASE WHEN quarter = 'Q1' THEN revenue ELSE 0 END) AS q1_rev,
  SUM(CASE WHEN quarter = 'Q2' THEN revenue ELSE 0 END) AS q2_rev
FROM   quarterly_sales
GROUP BY company_name;
ELSE 0 vs ELSE NULL の違い:ELSE 0 は対象外の行を 0 として合計します。ELSE NULL にすると SUM は NULL を無視するため結果は同じですが、AVG や COUNT に影響が出ます。ピボット集計では慣習的に ELSE 0 が使われます。
問題

3社の2024年四半期売上から、四半期別売上(第1〜第4四半期)を横持ちに変換し、年間合計(annual_total)と 第1四半期→第4四半期の年内成長率(q4_vs_q1_pct、小数第1位)を算出してください。取得列は company_name, q1_rev, q2_rev, q3_rev, q4_rev, annual_total, q4_vs_q1_pct、annual_total 降順で返してください。

使用テーブル
▸ quarterly_sales
company_nameyearquarterrevenue
AlphaTech2024Q1340
AlphaTech2024Q2410
AlphaTech2024Q3320
AlphaTech2024Q4450
BetaSoft2024Q1260
BetaSoft2024Q2240
BetaSoft2024Q3310
BetaSoft2024Q4340
GammaSys2024Q1130
GammaSys2024Q2165
GammaSys2024Q3185
GammaSys2024Q4170

※ revenue 単位: 億円

期待出力
company_nameq1_revq2_revq3_revq4_revannual_totalq4_vs_q1_pct
AlphaTech340410320450152032.4
BetaSoft260240310340115030.8
GammaSys13016518517065030.8
QUESTION 10

PERCENT_RANK() + LAG() + 2段 CTE — 競合の相対ポジション変化を年次追跡する

PERCENT_RANKLAG + 2段CTE相対ポジション変化パーセンタイル追跡
前提知識

PERCENT_RANK() は各行の相対的な順位をパーセンタイル(0.0〜1.0)で返します。計算式は (rank - 1) / (total_rows - 1) です。

計算式5行の例(ORDER BY revenue ASC)
(rank-1) / (5-1)最小売上=0.0 / 中位=0.5 / 最大売上=1.0
PERCENT_RANK() OVER (
  PARTITION BY year             -- 年度ごとに独立した順位空間
  ORDER BY     revenue_bn       -- 小さい順→0.0、大きい順→1.0
) * 100                         -- 百分率(0〜100)に変換
2段 CTE による依存処理:「PERCENT_RANK を計算」→「前年の PERCENT_RANK を LAG で取得」という2ステップは依存関係があるため、1段目 CTE で pct_rank を確定させ、2段目 CTE で LAG を適用する構造になります。
問題

5社の2年分の売上データから、年度内での相対売上ポジション(pct_rank、小数第1位・百分率)と前年比ポジション変化(pct_rank_changeを算出してください。取得列は company_name, year, revenue_bn, pct_rank, prev_pct_rank, pct_rank_change、year 昇順 → pct_rank 降順で返してください。

使用テーブル
▸ annual_performance
company_nameyearrevenue_bn
AlphaTech202235.0
BetaSoft202226.0
GammaSys202218.0
DeltaNet202212.0
EpsilonSys20227.0
AlphaTech202342.0
BetaSoft202328.0
GammaSys202315.0
DeltaNet202316.0
EpsilonSys20239.0
期待出力
company_nameyearrevenue_bnpct_rankprev_pct_rankpct_rank_change
AlphaTech202235.0100.0NULLNULL
BetaSoft202226.075.0NULLNULL
GammaSys202218.050.0NULLNULL
DeltaNet202212.025.0NULLNULL
EpsilonSys20227.00.0NULLNULL
AlphaTech202342.0100.0100.00.0
BetaSoft202328.075.075.00.0
DeltaNet202316.050.025.025.0
GammaSys202315.025.050.0-25.0
EpsilonSys20239.00.00.00.0