標準はあるにはあるが癖の多いSQL 全部俺w Advent Calendar 2020の14日目です。
今回は大作(軽めにしたかったけど、少々難しのでそのまま載せることにしました)
業務上あまり多くないですが、一連番号の集合を作りたくなることがあります。シーケンスを使わずに。。
Oracleには昔から比較的簡単なクエリーで一連番号の集合を作り出せる(本来その目的のた目のクエリーではないですが)クエリーがいくつかあります。
PostgreSQLには、8.0(7.xぐらいから存在していたのか調べきれず。間違っていたらコメントいただけると助かります)ぐらいから 集合を返す関数として、generate_series()が組み込まれています。
MySQLは調べた限りですが、その手の便利関数やクエリーはあまりなさそうでした。
でそれを救う救世主w と言うのは大げさですが、WITH句を使った再帰問い合わせを使うと比較的互換の高い利用ができるようになってきました。
完全に同一構文ということではないのですけども。。。書き換える部分は少ない方だと思います:)
では、
Oracleから
まず、方言から古い順に紹介していきます。
Oracle/その1:階層問合せとlevel擬似列を利用する方法
他の方法に比べると処理時間なども有利ではあるのですが、Oracleだけでしか利用できない方法です。昔から利用している方は手グセでこちらをタイプすることも多いはずw
実行計画もシンプルで、Oracleで利用可能な方法の中では負荷は軽め(私が検証した範囲では)
階層問合せか、再帰問合せか、それが問題だ #2
https://discus-hamburg.cocolog-nifty.com/mac_de_oracle/2011/01/2-8488.html
階層問合せ
https://docs.oracle.com/cd/F19136_01/sqlrf/Hierarchical-Queries.html#GUID-0118DF1D-B9A9-41EB-8556-C6E7D6A5A84E
ORACLE> set tab off ORACLE> set linesize 300 ORACLE> r 1 SELECT 2 LEVEL AS r 3 FROM 4 dual 5 CONNECT BY 6 LEVEL <= 10 7*
R ---------- 1 2 3 4 5 6 7 8 9 10
10 rows selected. Elapsed: 00:00:00.10 ORACLE>ORACLE> set autot trace exp ORACLE> r ...略...
Execution Plan ---------------------------------------------------------- Plan hash value: 1236776825
----------------------------------------------------------------------------- | Id | Operation | Name | Rows | Cost (%CPU)| Time | ----------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 2 (0)| 00:00:01 | |* 1 | CONNECT BY WITHOUT FILTERING| | | | | | 2 | FAST DUAL | | 1 | 2 (0)| 00:00:01 | -----------------------------------------------------------------------------
Predicate Information (identified by operation id): ---------------------------------------------------
1 - filter(LEVEL<=10)
|
Oracle/その2:CUBEとrownum擬似列を利用する方法
これOracle 8iぐらいから拡張されたという記憶(間違ってたらごめんなさい)が、CUBEというクロス集計が簡単に書ける構文で長いクエリー書かなくて済むようになったーーーと
リリースされた当時は嬉しかった拡張の一つです。こんな使い方もできるのなーというところですが、実行計画を見るとかなり重めなんですよね。実際階層問合せより重いので、一連番号生成目的で利用することはほぼないですが、できるということで紹介しておきます。
20.3 CUBE(GROUP BYの拡張)
https://docs.oracle.com/cd/F19136_01/dwhsg/sql-aggregation-data-warehouses.html#GUID-C5FDD050-DCE0-4FE1-9741-420E2F970A36
ROWNUM疑似列
https://docs.oracle.com/cd/F19136_01/sqlrf/ROWNUM-Pseudocolumn.html#GUID-2E40EC12-3FCF-4A4F-B5F2-6BC669021726
ORACLE> r 1 SELECT rownum 2 FROM 3 ( 4 SELECT 1 5 FROM 6 dual 7 GROUP BY 8 CUBE(1,1,1,1,1) 9 ) 10 WHERE 11* rownum <= 10
ROWNUM ---------- 1 2 3 4 5 6 7 8 9 10
10 rows selected. Elapsed: 00:00:00.16
Execution Plan ---------------------------------------------------------- Plan hash value: 2264780677
---------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 66 (0)| 00:00:01 | |* 1 | COUNT STOPKEY | | | | | | | 2 | VIEW | | 1 | | 66 (0)| 00:00:01 | | 3 | TEMP TABLE TRANSFORMATION | | | | | | | 4 | MULTI-TABLE INSERT | | | | | | | 5 | SORT GROUP BY NOSORT ROLLUP | | 1 | | 2 (0)| 00:00:01 | | 6 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 7 | DIRECT LOAD INTO (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D698E_276CE9B | | | | | | 8 | DIRECT LOAD INTO (CURSOR DURATION MEMORY)| SYS_TEMP_0FD9D698F_276CE9B | | | | | | 9 | VIEW | | 32 | 416 | 64 (0)| 00:00:01 | | 10 | VIEW | | 32 | 416 | 64 (0)| 00:00:01 | | 11 | UNION-ALL | | | | | | | 12 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 13 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 14 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 15 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 16 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 17 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 18 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 19 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 20 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 21 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 22 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 23 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 24 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 25 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 26 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 27 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 28 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 29 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 30 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 31 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 32 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 33 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 34 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 35 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 36 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 37 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 38 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 39 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 40 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 41 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 42 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698E_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | | 43 | TABLE ACCESS FULL | SYS_TEMP_0FD9D698F_276CE9B | 1 | 13 | 2 (0)| 00:00:01 | ----------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id): ---------------------------------------------------
1 - filter(ROWNUM<=10)
|
Oracle/その3:再帰問合せを利用する方法
冒頭で紹介した階層問合せはOracleの方言ばりばりですが、階層問合せをサポートしているエンジンも多くなってきたこともあり、同一構文とまでは行きませんがかなり互換性は高い方法です。
汎用性のある方法にしたい場合は階層問合せを利用しておくと良いかもしれませんね。
Oracleの再帰問合せ構文では、recursive がないのが大きな違いです。また、dual表の利用も必要なのでこの点が他のエンジンと違うところと思っておけば大丈夫だと思います。
意外と構文はシンプルです。階層問合せに比べるとタイプする文字列は多いですけどw
再帰的副問合せのファクタリング
https://docs.oracle.com/cd/F19136_01/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6
ORACLE> r 1 WITH gen_nums(v) 2 AS 3 ( 4 SELECT 1 5 FROM 6 dual 7 UNION ALL 8 SELECT v + 1 9 FROM 10 gen_nums 11 WHERE v + 1 <= 10 12 ) 13 SELECT v from gen_nums 14*
V ---------- 1 2 3 4 5 6 7 8 9 10
10 rows selected. Elapsed: 00:00:00.16
Execution Plan ---------------------------------------------------------- Plan hash value: 1492144221
-------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 2 | 26 | 4 (0)| 00:00:01 | | 1 | VIEW | | 2 | 26 | 4 (0)| 00:00:01 | | 2 | UNION ALL (RECURSIVE WITH) BREADTH FIRST| | | | | | | 3 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | |* 4 | RECURSIVE WITH PUMP | | | | | | --------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id): ---------------------------------------------------
4 - filter("V"+1<=10)
|
最近のコメント