SAK 図書館
SQL 問い合わせ - スカラー副問い合わせ、cursor、row_number、over、with
■スカラー副問い合わせ (Oracle9i 以降) ・最近の Oracle は何でもありです。 このスカラー副問い合わせは、広く応用できて非常に便利です。 尚、フィールドなど単一行の結果を戻す必要のある問い合わせを 単一行副問い合わせと呼ぶ。 (単1行副問い合わせ、単一行問い合わせ、単1行問い合わせ) select 受注番号, 品番, (select 在庫数 from 品番v1 b where b.品番 = a.品番) 在庫数 from 受注m a ; select 受注番号, 品番, (select sum(受注数) from 受注m b where b.品番 = a.品番) 受注数計 from 受注m a ; select 品番, コード1, (select コード名 from コードm b where b.コード = a.コード1) コード名1, コード2, (select コード名 from コードm b where b.コード = a.コード2) コード名2 from 品番m a ; ・from 句に副問い合わせを書くこともできる。 この書式は Oracle8 ぐらいから使えた。 これをインラインビューと呼ぶ。 select * from (select * from 受注m where 品番 like 'a%') a where a.受注数 > 1000 ; ■CURSOR (Oracle9i 以降) ・cursor() は、このスカラー副問い合わせに似ているのですが、こちらは 複数の列を返すことが出来ます。 select 受注番号, 品番, cursor( select 在庫数, 受注数 受注累積 from 品番v1 b where b.品番 = a.品番 ) 在庫数 from 受注m a ; ■ROWNUM (Oracle8i 以降?) ・先頭から 10 件問い合わせるには、次のようにする。 access の top と同じことができる。 row_number の方も非常に便利である。 (TOP 10 取得、表示行制限、レコード数限定、件数指定、表示件数) (1 レコード取得、1 件取得) select rownum, 受注番号, 品番, 受注数 from 受注m where rownum <= 10 ; ROWNUM 受注番号 品番 受注数 ---------- ---------- ------------------ ---------- 1 000001-002 a001 500 2 000001-001 a001 70 3 000001-056 a001 500 4 000001-057 b001 2000 5 000001-058 a001 500 6 000001-059 a001 500 7 000001-060 a001 500 8 000001-061 c001 1500 9 000001-062 a001 500 10 000001-063 a001 501 ・但し、order by 句があると、rownum の順序が変わってしまう。 select rownum, 受注番号, 品番, 受注数 from 受注m where rownum <= 10 order by 受注数 desc; ; ROWNUM 受注番号 品番 受注数 --------- ---------- ------------------ ---------- 4 000001-057 b001 2000 8 000001-061 c001 1500 10 000001-063 a001 501 1 000001-002 a001 500 3 000001-056 a001 500 6 000001-059 a001 500 9 000001-062 a001 500 7 000001-060 a001 500 5 000001-058 a001 500 2 000001-001 a001 70 ・order by 句がある場合、次のようにすると良い。 select rownum, 受注番号, 品番, 受注数 from (select 受注番号, 品番, 受注数 from 受注m order by 受注数 desc) where rownum <= 10 ; ROWNUM 受注番号 品番 受注数 ---------- ---------- ------------------ ---------- 1 000011-001 b001 6000 2 000019-001 b001 5555 3 100011-002 c001 4500 4 000004-001 a001 4000 5 000546-001 b001 3000 6 000001-057 b001 2000 7 000001-061 c001 1500 8 000001-078 a001 549 9 000001-063 a001 501 10 000001-002 a001 500 ・rownum = 2、rownum > 1 は使えない。 select rownum, 受注番号, 品番, 受注数 from (select 受注番号, 品番, 受注数 from 受注m order by 受注数 desc) where rownum > 2 ; ** 処理不能 - レコードが選択されませんでした ■ROW_NUMBER (Oracle9i 以降?) ・シーケンス番号を返してくれる。 使い方で access の top と同じことができる。 但し、rownum の方が処理は速いかもしれない。 (TOP 10 取得、表示行制限、レコード数限定、件数指定、表示件数、TOP 値) (何件目のレコード、1レコード表示、1レコードのみ表示、トップ値) (トップ N 分析、トップ N 問い合わせ、TOP N 分析、TOP N 問い合わせ) (1 レコード取得、1 件取得) select row_number() over (order by 受注数 desc) ct , 受注番号, 品番, 受注数 from 受注m order by 受注数 desc; ・先頭から 10 件問い合わせるには、次のようにする。 select * from ( select row_number() over (order by 受注数 desc) ct , 受注番号, 品番, 受注数 from 受注m order by 受注数 desc ) where ct <= 10 ; CT 受注番号 品番 受注数 ---------- ---------- ------------------ ---------- 1 000011-001 b001 6000 2 000019-001 b001 5555 3 100011-002 c001 4500 4 000004-001 a001 4000 5 000546-001 b001 3000 6 000001-057 b001 2000 7 000001-061 c001 1500 8 000001-078 a001 549 9 000001-063 a001 501 10 000001-002 a001 500 ・先頭レコードを問い合わせるには、次のようにする。 (1 件取得) select * from ( select row_number() over (order by 受注数 desc) ct , 受注番号, 品番, 受注数 from 受注m order by 受注数 desc ) where ct = 1 ; CT 受注番号 品番 受注数 --------- ---------- ------------------ ---------- 1 000011-001 b001 6000 ・最終からと言うのは、元になる SQL のソートオーダを逆にする。 ソートオーダを逆に先頭から 10 件問い合わせるには、次のようにする。 select * from ( select row_number() over (order by 受注数) ct , 受注番号, 品番, 受注数 from 受注m order by 受注数 ) where ct <= 10 ; CT 受注番号 品番 受注数 --------- ---------- ------------------ ---------- 1 000628-001 a001 10 2 000746-001 a001 10 3 000921-001 c001 10 4 000010-001 b001 20 5 000002-001 a001 60 6 000003-001 a001 60 7 000001-001 a001 70 8 000643-001 a001 100 9 006589-001 a001 100 10 730001-001 a001 100 ・rownum では指定できない条件も row_number ならできる。 select * from ( select row_number() over (order by 受注数) ct , 受注番号, 品番, 受注数 from 受注m order by 受注数 ) where ct >= 10 and ct <= 20 ; CT 受注番号 品番 受注数 --------- ---------- ------------------ ---------- 10 730001-001 a001 100 11 741001-001 a001 100 12 006589-002 a001 100 13 000800-001 a001 100 14 002301-001 a001 101 15 004601-001 a001 101 16 100011-001 b001 111 17 100011-003 b001 111 18 000001-002 a001 500 19 000001-056 a001 500 20 000001-059 a001 500 ■CASE (Oracle9i 以降) ・ほんと、なんでもできるなあ〜。 select 受注番号, 品番, case when 受注数 < 1000 then '少ない' else '多い' end from 受注m; ・受注数が 1000 以上のものだけ合計する。 select 品番, sum( case when 受注数 < 1000 then 0 else 受注数 end) from 受注m group by 品番; ■EXISTS (Oracle8i 以降?) ・副問い合わせが行を戻したか。 select * from 受注m a where exists (select * from 品番m b where b.品番 = a.品番); ■FIRST、LAST (Oracle9i 以降) ・複雑すぎてちょっと難解である。 select 品番, max(受注数), min(受注数) from 受注m group by 品番 ; ・次の例は、最も新しい更新日付の品番の最大受注数と 最も古い更新日付の品番の最小受注数が返る。 select 品番, max(受注数) keep (dense_rank last order by 更新日付) a, min(受注数) keep (dense_rank first order by 更新日付) b from 受注m group by 品番 ; ・明細で返すこともできる。 これも使い道がいまひとつわからない。 select 品番, max(受注数) keep (dense_rank last order by 更新日付) over (partition by 品番) a, min(受注数) keep (dense_rank first order by 更新日付) over (partition by 品番) b from 受注m order by 品番 ; ■WITH (Oracle9i 以降) ・複雑な SQL をすっきり書くためのものなのだろうか。 with sel1 as ( select * from 受注m order by 受注番号 ), sel2 as ( select avg(受注数) 受注数 from 受注m ) select * from sel1 where 受注数 > (select * from sel2) ; ・sel2 で sel1 を使用することもできるらしい。 けっこう複雑な SQL が作れそうである。 with sel1 as ( select * from 受注m order by 受注番号 ), sel2 as ( select avg(受注数) 受注数 from sel1 ) select * from sel1 where 受注数 > (select * from sel2) ; ■FIRST_VALUE、LAST_VALUE (Oracle8i 以降) ・いまひとつ使い道がわかんない。 条件に一致する最初、または、最後の 1 件を取得する。 select 受注番号, 品番, first_value(品番) over (order by 品番 asc rows unbounded preceding) as 品番, last_value(品番) over (order by 品番 asc rows unbounded preceding) as 品番 from 受注m order by 受注番号 ; ■GROUP_ID (Oracle9i 以降) ・いまひとつ使い道がわかんない。 select 品番, max(受注数), min(受注数), group_id() from 受注m group by 品番 ; ■SQL 基礎実地編資料
■SQL 基礎編資料
■SQL チューニング編資料
■Oracle PL/SQL 編資料
■PostgreSQL 編、JAVA Servlet、JSP 編資料
■MySQL 編資料