チーム内の雑談で、
Delete-Insert処理を1つのSQL文で行うとしたら、
SELECT文のSELECT句でDELETE用SPとINSERT用SPを呼び出す方法もあるよね、
SELECT句って記述順に実行してくれるのかな?
みたいな話になったので、検証してみた。
検証してみる
検証環境はCentOS環境上のPostgreSQL 9.5。
SPを使うのはちょっと面倒なので、
タイムスタンプを取得する関数で試してみる。
current_timestampやnow()は何度呼び出してもトランザクション開始時の時刻を
返してくれちゃうので、実際の現在時刻を返すclock_timestamp()を使う。
select clock_timestamp() as x, clock_timestamp() as y;
結果:
x | y -------------------------------+------------------------------- 2016-10-29 01:28:21.347312+09 | 2016-10-29 01:28:21.347314+09 (1 行)
順序通りに実行されてるようだ。
一方now()だとこうなる。
select now() as x, now() as y;
結果:
x | y -------------------------------+------------------------------- 2016-10-29 01:15:41.942841+09 | 2016-10-29 01:15:41.942841+09 (1 行)
上記のマニュアルページでpg_sleepという遅延実行関数を見つけたので、
clock_timestamp()の間に1秒のsleep処理を挟んで試してみる。
select clock_timestamp() as x, pg_sleep(1), clock_timestamp() as y, pg_sleep(1), clock_timestamp() as z;
結果:
x | pg_sleep | y | pg_sleep | z -------------------------------+----------+------------------------------+----------+------------------------------- 2016-10-29 01:29:11.397228+09 | | 2016-10-29 01:29:12.39835+09 | | 2016-10-29 01:29:13.399481+09 (1 行)
ちゃんと1秒間隔で関数が実行されており、期待通りの良い感じ。
FROM句での実行についても試してみる。
select t1.t as x, t2.t as y, t3.t as z, t1.t as x2 from (select clock_timestamp() as t, pg_sleep(1)) as t1, (select clock_timestamp() as t, pg_sleep(1)) as t2, (select clock_timestamp() as t, pg_sleep(1)) as t3 ;
結果:
x | y | z | x2 -------------------------------+-------------------------------+-------------------------------+------------------------------- 2016-10-29 01:31:41.524409+09 | 2016-10-29 01:31:42.525554+09 | 2016-10-29 01:31:43.526694+09 | 2016-10-29 01:31:41.524409+09 (1 行)
x(t1)->y(t2)->z(t3)のFROM句記述順で実行されてる。
x2は確認用にxと同じt1の結果を表示しており、xと同じ値を返してるので
FROM句の処理時のタイムスタンプが返されてることが分かる。
一応、SELECT句での呼び出しではなくFROM句の順序に依存していることを
確認するために、FROM句の順序を入れ替えてみる。
select t1.t as x, t2.t as y, t3.t as z, t1.t as x2 from (select clock_timestamp() as t, pg_sleep(1)) as t3, (select clock_timestamp() as t, pg_sleep(1)) as t2, (select clock_timestamp() as t, pg_sleep(1)) as t1 ;
x | y | z | x2 -------------------------------+-------------------------------+-------------------------------+------------------------------- 2016-10-29 02:33:01.384055+09 | 2016-10-29 02:33:00.383529+09 | 2016-10-29 02:32:59.382388+09 | 2016-10-29 02:33:01.384055+09 (1 行)
z(t1)->y(t2)->x(t3)のFROM句記述順で実行されてるようだ。
with句でも試してみよう。
with t1 as (select clock_timestamp() as t, pg_sleep(1)) ,t2 as (select clock_timestamp() as t, pg_sleep(1)) ,t3 as (select clock_timestamp() as t, pg_sleep(1)) select t1.t as x, t2.t as y, t3.t as z, t1.t as x2 from t1,t2,t3 ;
結果:
x | y | z | x2 -------------------------------+-------------------------------+-------------------------------+------------------------------- 2016-10-29 03:12:55.630785+09 | 2016-10-29 03:12:56.632065+09 | 2016-10-29 03:12:57.633293+09 | 2016-10-29 03:12:55.630785+09 (1 行)
FROM句入れ替え版
with t1 as (select clock_timestamp() as t, pg_sleep(1)) ,t2 as (select clock_timestamp() as t, pg_sleep(1)) ,t3 as (select clock_timestamp() as t, pg_sleep(1)) select t1.t as x, t2.t as y, t3.t as z, t1.t as x2 from t3,t2,t1 ;
x | y | z | x2 -----------------------------+-------------------------------+-------------------------------+----------------------------- 2016-10-29 03:13:39.9427+09 | 2016-10-29 03:13:38.941544+09 | 2016-10-29 03:13:37.940425+09 | 2016-10-29 03:13:39.9427+09 (1 行)
with句の記述順ではなく、FROM句の呼び出し順で実行されている。
おわり
SELECT句もFROM句も関数呼び出しは記述順で実行してくれるようなので、
Delete用SPとInsert用SPをSELECT句で並べて実行する方法は
(それが良い方法かどうかはともかくとして)うまくいきそう。
clock_timestamp()とpg_sleep()は良い発見だった。
- 作者: 笠原辰仁,北川俊広,坂井潔,坂本昌彦,佐藤友章,石井達夫
- 出版社/メーカー: 翔泳社
- 発売日: 2011/02/02
- メディア: 大型本
- 購入: 3人 クリック: 28回
- この商品を含むブログ (6件) を見る