SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

分析関数の衝撃

分析関数の衝撃(後編)

CodeZineに掲載されたSQLを分析関数で記述する 3

  • X ポスト
  • このエントリーをはてなブックマークに追加

ダウンロード ソースコード (3.7 KB)

3人なんですけど座れますか? - その2:行の折り返しも考慮する

 次に人数分の空席を探すSQL(行の折り返しも考慮する)についてです。「SQLで数列を扱う」では、以下のSQLが提示されています。

人数分の空席を探す その2:行の折り返しも考慮する
SELECT S1.seat   AS start_seat, '~' , S2.seat AS end_seat
  FROM Seats2 S1, Seats2 S2
 WHERE S2.seat = S1.seat + (:head_cnt -1)  --始点と終点を決める
   AND NOT EXISTS
          (SELECT *
             FROM Seats2 S3
            WHERE S3.seat BETWEEN S1.seat AND S2.seat
              AND (    S3.status <> '空'
                    OR S3.row_id <> S1.row_id));

 これを分析関数で書き換えてみます。まずは、テーブルのデータと、出力結果を考えます。

Seats2テーブル
seatrow_idstatus
1A
2A
3A
4A
5A
6B
7B
8B
9B
10B
11C
12C
13C
14C
15C
出力結果
row_idSeatStartSeatEnd
A35
B810
C1113

 手続き型の言語であれば、

  1. row_idの昇順、seatの昇順にソート
  2. 各値を、配列に保存
  3. 配列の添字の最小値からループ
  4. 配列の添字を元に、row_idが等しい、3つの連続した空席を探す

 といった処理を行うと思いますが、分析関数を使ったSQLでも似たような考え方を使います。

分析関数で書き換えたSQL
select Row_ID,SeatStart,SeatEnd
from (select Row_ID,
      seat as SeatStart,
      Lead(seat,3-1)
      over(partition by Row_ID order by seat) as SeatEnd,
      count(nullif(status,'占'))
      over(partition by Row_ID order by seat
           Rows between current row
                    and (3-1) following) as SeatCount
      from Seats2)
where SeatCount = 3;

 インラインビューの中のselect文にstatus列を追加した、SQLのイメージはこうなります。

SQLのイメージ
SQLのイメージ

 SQL自体は前の、「3人なんですけど座れますか? その1:行の折り返しを考慮しない」で使った分析関数に、partition by句で「Row_ID」を指定して、「Row_ID」でパーティションを切っただけとなります。SQLのイメージを比較すると分かりやすいと思います。

 DB2では、下記のSQLとなります。

分析関数で書き換えたSQL(DB2)
select Row_ID,SeatStart,SeatEnd
from (select Row_ID,
      seat as SeatStart,
      max(seat) over(partition by Row_ID
                     order by seat
                     Rows between 2 following
                              and 2 following) as SeatEnd,
      count(nullif(status,'占'))
      over(partition by Row_ID order by seat
           Rows between current row
                    and 2 following) as SeatCount
      from Seats2) dummy
where SeatCount = 3;

--これでも可
select Row_ID,SeatStart,SeatEnd
from (select Row_ID,
      seat as SeatStart,
      max(seat) over(partition by Row_ID
                     order by seat
                     Rows between 2 following
                              and 2 following) as SeatEnd,
      count(nullif(status,'占'))
      over(partition by Row_ID order by seat
           Rows 2 following) as SeatCount
      from Seats2) dummy
where SeatCount = 3;

次のページ
最大何人まで座れますか?

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
分析関数の衝撃連載記事一覧

もっと読む

この記事の著者

山岸 賢治(ヤマギシ ケンジ)

趣味が競技プログラミングなWebエンジニアで、OracleSQLパズルの運営者。AtCoderの最高レーティングは1204(水色)。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/1299 2007/09/14 14:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング