SHOEISHA iD

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

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

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

達人に学ぶSQL

SQLで数列を扱う

SQLにおける順序を持ったデータの取り扱い方


最大何人まで座れますか?

 次に取り上げるのは、前問の裏返しの問題です。すなわち、「現在の空席状況だと、最大で何人が連続で座れるか」を調べる、というものです。換言するなら最大シーケンスを求める問題です。次のような「Seats3」テーブルを使います。

Seats3
seat(座席) status(状態)
1
2
3
4
5
6
7
8
9
10

 このサンプル・データだと、大きさ4の「2~5」のシーケンスが答えになります。この問題を解くには、最初にシーケンスをすべてリストアップするビューを作るのが簡単です。そうすれば、後はそのビューから最大のシーケンスを選択するだけです。

 「Seats3」テーブルにおいて、ある席番号Aから別の席番号Bまでがシーケンスである、ということを保証するには、以下の三つの条件をすべて満たすことです。

  • 条件1.始点―終点間のすべての座席の状態が「空」である
  • 条件2.始点の1つ前の座席の状態が「空」ではない
  • 条件3.終点の1つ後の座席の状態が「空」ではない

 例えば、条件1についてみると、次のように途中に「占」の席があったりしたら、その期間がシーケンス失格なことは明らかです。

 

 同様に、始点と終点をもっと伸ばせるような期間も、やはり選択対象からは除外します(その伸ばした始点と終点を持つ期間があれば十分ですから)。

条件2を満たさないケース
条件2を満たさないケース
条件3を満たさないケース
条件3を満たさないケース

 この問題でも、前問と同様にステップ1とステップ2の手順を踏むことで、次のようなビューが作れます。

第1段階:すべてのシーケンスを保持するビューを作る。
CREATE VIEW Sequences (start_seat, end_seat, seat_cnt) AS
SELECT S1.seat  AS start_seat,
       S2.seat  AS end_seat,
       S2.seat - S1.seat + 1 AS seat_cnt
  FROM Seats3 S1, Seats3 S2
 WHERE S1.seat <= S2.seat  --ステップ1:始点と終点の組み合わせを作る
   AND NOT EXISTS 
      --ステップ2:シーケンス内のすべての行が満たすべき条件を記述する
       (SELECT *
          FROM Seats3 S3
         WHERE (     S3.seat BETWEEN S1.seat AND S2.seat 
                 AND S3.status <> '空')  --条件1の否定
            OR  (S3.seat = S2.seat + 1 AND S3.status = '空' )
                                                         --条件2の否定
            OR  (S3.seat = S1.seat - 1 AND S3.status = '空' ));  
                                                         --条件3の否定

 このビューは、次のような内容を含みます。

start_seat    end_seat    seat_cnt
------------  ----------  ----------
         2           5           4
         7           7           1
         9          10           2

 大きさが1の「7~7」をシーケンス(連番)と呼ぶのは語義矛盾の気もしますが、今回は一応含めています(もし大きさ1の集合を除外したければ、WHERE句の「S1.seat <= S2.seat」の等号を除いてください)。

 ここまで来れば、後は簡単です。このビューから、席数(seat_cnt)が最大の行を選択しましょう。

第2段階:最大のシーケンスを求める
SELECT start_seat, '~', end_seat, seat_cnt
  FROM Sequences
 WHERE seat_cnt = (SELECT MAX(seat_cnt) FROM Sequences);

 この問題においても、まずはステップ1に従い、自己結合(S1.seat <= S2.seat)で、始点と終点の組み合わせを作っています。これは、ランキングや累計を求めるクエリと同じ非等値結合です。

 そして始点と終点が決まったら、今度はその内部のすべての行が満たすべき条件を記述するために、始点と終点の間を移動するS3を追加することや、全称文を存在文の否定に同値変形することも、前問とまったく同じです(今回はさらに、S3に両端の1つ外側の点も代表させていますが)。

 この2つのステップが、SQLで順序集合を扱うときの定石です。次の最終問題も、この2点を意識して考えてください。今度は、発展版として「第四の集合」まで使います。

次のページ
単調増加と単調減少

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

達人に学ぶSQL連載記事一覧

もっと読む

この記事の著者

ミック(ミック)

日本では、主にBI/DWHの設計からチューニングまでを専門とするデータベースエンジニアとして活動。2018年より米国シリコンバレーに活動拠点を移し、技術調査とビジネス開発に従事している。主な著書・訳書:『達人に学ぶSQL徹底指南書 第2版』(2018)『SQL実践入門』(2015)Joe Celko『プログラマのためのSQL 第4版』(2015)翔泳社 - 著者ページ:https://www.shoeisha.co.jp/book/author/3964著者個人ページ:http://mickindex.sakura.ne.jp/

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

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

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/1076 2008/09/03 13:40

イベント

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

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

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

メールバックナンバー