118
Webで役立つRDBの使い方 第九回 中国地方DB勉強会 in 米子

Webで役立つRDBの使い方

Embed Size (px)

Citation preview

Page 1: Webで役立つRDBの使い方

Webで役立つRDBの使い方第九回 中国地方DB勉強会 in 米子

Page 2: Webで役立つRDBの使い方

What is it?

データベースは何を基準に選んでますか?

Page 3: Webで役立つRDBの使い方

What is it?

RDBを制する者は

データ層を制する

と言っても過言ではありません

Page 4: Webで役立つRDBの使い方

What is it?今日は

アプリを書く上で便利な事

をご紹介します

Page 5: Webで役立つRDBの使い方

What is it?ただし

インデックスやDB設計

の話は今日はしません

Page 6: Webで役立つRDBの使い方

What is it?

主にSQLの話です

Page 7: Webで役立つRDBの使い方

What is it?

MySQLやPostgreSQLを使う人の

今日から使える便利な知識(SQL)

を持ち帰って活用してください

Page 8: Webで役立つRDBの使い方

あじぇんだ

1 自己紹介 2 連番を作る 3 クエリを減らす 4 まとめ

Page 9: Webで役立つRDBの使い方

あじぇんだ

1 自己紹介 2 連番を作る 3 クエリを減らす 4 まとめ

Page 10: Webで役立つRDBの使い方

自己紹介名前:曽根 壮大(そね たけとも) 年齢:30歳(三人の子供がいます) 職業:Webエンジニア

所属:日本PostgreSQLユーザ会

   中国支部 支部長

  技術的にはLL系言語とかRDBが好きです

Page 11: Webで役立つRDBの使い方

あじぇんだ

1 自己紹介 2 連番を作る 3 クエリを減らす 4 まとめ

Page 12: Webで役立つRDBの使い方

連番を作る

検索結果に合わせて連番を作る

Page 13: Webで役立つRDBの使い方

ID 名前 戦闘力 編

1 フリーザ 530000 フリーザ編

2 悟飯(幼少期) 1307 ラディッツ編

3 クリリン 206 ラディッツ編

4 ヤムチャ 177 ラディッツ編

5 農夫 5 ラディッツ編

6 ギニュー 120000 フリーザ編

7 クリリン 1500 フリーザ編

8 亀仙人 139 ラディッツ編

※実務では編は正規化するべき

Page 14: Webで役立つRDBの使い方

連番を作る

MySQLの場合

Page 15: Webで役立つRDBの使い方

連番を作る

MySQLの場合 ↓

SQLの中で変数が使える

Page 16: Webで役立つRDBの使い方

MySQLの場合SET @num := 0;

SELECT

(@num := @num + 1) AS serial,

キャラクター.*

FROM キャラクター

ORDER BY 戦闘力 DESC;

Page 17: Webで役立つRDBの使い方

MySQLの場合SET @num := 0;

SELECT

(@num := @num + 1) AS serial,

キャラクター.*

FROM キャラクター

ORDER BY 戦闘力 DESC;

変数宣言

Page 18: Webで役立つRDBの使い方

MySQLの場合SET @num := 0;

SELECT

(@num := @num + 1) AS serial,

キャラクター.*

FROM キャラクター

ORDER BY 戦闘力 DESC;

変数宣言

変数をインクリメントしながら表示

Page 19: Webで役立つRDBの使い方

MySQLの場合SELECT

(@num := @num + 1) AS serial,

キャラクター.*

FROM キャラクター,

(SELECT @num := 0 ) AS base

ORDER BY 戦闘力 DESC;

Page 20: Webで役立つRDBの使い方

MySQLの場合SELECT

(@num := @num + 1) AS serial,

キャラクター.*

FROM キャラクター,

(SELECT @num := 0 ) AS base

ORDER BY 戦闘力 DESC;

変数宣言をテーブルとして行い、 JOINすることで1回のクエリにする

Page 21: Webで役立つRDBの使い方

連番 ID 名前 戦闘力 編

1 1 フリーザ 530000 フリーザ編

2 6 ギニュー 120000 フリーザ編

3 7 クリリン 1500 フリーザ編

4 2 悟飯(幼少期) 1307 ラディッツ編

5 3 クリリン 206 ラディッツ編

6 4 ヤムチャ 177 ラディッツ編

7 8 亀仙人 139 ラディッツ編

8 5 農夫 5 ラディッツ編

※実行結果

Page 22: Webで役立つRDBの使い方

連番を作る

他の変数宣言の使い方

Page 23: Webで役立つRDBの使い方

MySQLの場合SET sql_mode = 'PIPES_AS_CONCAT';

SET @num := 1;

INSERT INTO users (name)

VALUES (

'soudai+' || (@num := @num + 1)

);

Page 24: Webで役立つRDBの使い方

MySQLの場合SET sql_mode = 'PIPES_AS_CONCAT';

SET @num := 1;

INSERT INTO users (name)

VALUES (

'soudai+' || (@num := @num + 1)

);

文字結合を||で出来るようにモード変更

Page 25: Webで役立つRDBの使い方

MySQLの場合SET sql_mode = 'PIPES_AS_CONCAT';

SET @num := 1;

INSERT INTO users (name)

VALUES (

'soudai+' || (@num := @num + 1)

);

INSERTを実行するたびに nameが変わる

文字結合を||で出来るようにモード変更

Page 26: Webで役立つRDBの使い方

ID 名前 作成日15 soudai+16 "2015-05-30 04:15:24"14 soudai+15 "2015-05-30 04:15:24"13 soudai+14 "2015-05-30 04:15:24"12 soudai+13 "2015-05-30 04:15:24"11 soudai+12 "2015-05-30 04:15:24"10 soudai+11 "2015-05-30 04:15:24"9 soudai+10 "2015-05-30 04:15:24"8 soudai+9 "2015-05-30 04:15:23"7 soudai+8 "2015-05-30 04:15:23"6 soudai+7 "2015-05-30 04:15:23"5 soudai+6 "2015-05-30 04:15:23"4 soudai+5 "2015-05-30 04:15:23"3 soudai+4 "2015-05-30 04:15:23"2 soudai+3 "2015-05-30 04:15:23"1 soudai+2 "2015-05-30 04:15:22"

※実行結果

Page 27: Webで役立つRDBの使い方

MySQLの変数宣言その他の使い方

Page 28: Webで役立つRDBの使い方

MySQLの変数宣言その他の使い方

1 帳簿などで連続した日付を作る

Page 29: Webで役立つRDBの使い方

MySQLの変数宣言その他の使い方

1 帳簿などで連続した日付を作る 2 テストデータの投入

Page 30: Webで役立つRDBの使い方

MySQLの変数宣言その他の使い方

1 帳簿などで連続した日付を作る 2 テストデータの投入 3 一時的にデータを保持をする

Page 31: Webで役立つRDBの使い方

MySQLの変数宣言その他の使い方

1 帳簿などで連続した日付を作る 2 テストデータの投入 3 一時的にデータを保持をする

Page 32: Webで役立つRDBの使い方

MySQLの変数宣言注意点

変数展開は 「いつ実施されるか定まってない」

Page 33: Webで役立つRDBの使い方

MySQLの変数宣言注意点

JOINやサブクエリは 先にselect_listが評価される

↓ SELECT @num = @num+1

の+1が行われない

Page 34: Webで役立つRDBの使い方

MySQLの変数宣言注意点

JOINやサブクエリは 先にselect_listが評価される

↓ SELECT @num = @num+1

の+1が行われない

対象の列でORDER BYとかしてるとハマる (というかハマった)

Page 35: Webで役立つRDBの使い方

連番を作る

PostgreSQLの場合

Page 36: Webで役立つRDBの使い方

連番を作る

PostgreSQLの場合 ↓

SQL内での変数宣言が無い

Page 37: Webで役立つRDBの使い方

連番を作る

PostgreSQLの場合 ↓

Window関数を使う

Page 38: Webで役立つRDBの使い方

連番を作るウィンドウ関数

ウィンドウ関数は現在の行に何らの関係するテーブル行の一纏まり全般の計算を行う。

Page 39: Webで役立つRDBの使い方

PostgreSQLの場合SELECT

row_number()

OVER(

ORDER BY 戦闘力 DESC

) AS serial,

*

FROM キャラクター;

Page 40: Webで役立つRDBの使い方

PostgreSQLの場合SELECT

row_number()

OVER(

ORDER BY 戦闘力 DESC

) AS serial,

*

FROM キャラクター;

行番号を振る

Page 41: Webで役立つRDBの使い方

PostgreSQLの場合SELECT

row_number()

OVER(

ORDER BY 戦闘力 DESC

) AS serial,

*

FROM キャラクター;

行番号を振る

戦闘力で並べる

Page 42: Webで役立つRDBの使い方

連番 ID 名前 戦闘力 編

1 1 フリーザ 530000 フリーザ編

2 6 ギニュー 120000 フリーザ編

3 7 クリリン 1500 フリーザ編

4 2 悟飯(幼少期) 1307 ラディッツ編

5 3 クリリン 206 ラディッツ編

6 4 ヤムチャ 177 ラディッツ編

7 8 亀仙人 139 ラディッツ編

8 5 農夫 5 ラディッツ編

※実行結果

Page 43: Webで役立つRDBの使い方

連番 ID 名前 戦闘力 編

1 1 フリーザ 530000 フリーザ編

2 6 ギニュー 120000 フリーザ編

3 7 クリリン 1500 フリーザ編

4 2 悟飯(幼少期) 1307 ラディッツ編

5 3 クリリン 206 ラディッツ編

6 4 ヤムチャ 177 ラディッツ編

7 8 亀仙人 139 ラディッツ編

8 5 農夫 5 ラディッツ編

※実行結果

MySQLと同じ結果

Page 44: Webで役立つRDBの使い方

連番を作る

区分ごとのランキングも作れる

Page 45: Webで役立つRDBの使い方

PostgreSQLの場合SELECT

rank() OVER (

PARTITION BY "編"

ORDER BY "戦闘力" DESC

)

, *

FROM "キャラクター";

Page 46: Webで役立つRDBの使い方

PostgreSQLの場合SELECT

rank() OVER (

PARTITION BY "編"

ORDER BY "戦闘力" DESC

)

, *

FROM "キャラクター";

区分を指定する

Page 47: Webで役立つRDBの使い方

PostgreSQLの場合SELECT

rank() OVER (

PARTITION BY "編"

ORDER BY "戦闘力" DESC

)

, *

FROM "キャラクター";

区分ごとのランキング

区分を指定する

Page 48: Webで役立つRDBの使い方

RANK ID 名前 戦闘力 編

1 2 悟飯(幼少期) 1307 ラディッツ編

2 3 クリリン 206 ラディッツ編

3 4 ヤムチャ 177 ラディッツ編

4 8 亀仙人 139 ラディッツ編

5 5 農夫 5 ラディッツ編

1 1 フリーザ 530000 フリーザ編

2 6 ギニュー 120000 フリーザ編

3 7 クリリン 1500 フリーザ編

※実行結果

Page 49: Webで役立つRDBの使い方

RANK ID 名前 戦闘力 編

1 2 悟飯(幼少期) 1307 ラディッツ編

2 3 クリリン 206 ラディッツ編

3 4 ヤムチャ 177 ラディッツ編

4 8 亀仙人 139 ラディッツ編

5 5 農夫 5 ラディッツ編

1 1 フリーザ 530000 フリーザ編

2 6 ギニュー 120000 フリーザ編

3 7 クリリン 1500 フリーザ編

※実行結果

ラディッツ編で集計

フリーザ編で集計

Page 50: Webで役立つRDBの使い方

RANK ID 名前 戦闘力 編

1 2 悟飯(幼少期) 1307 ラディッツ編

2 3 クリリン 206 ラディッツ編

3 4 ヤムチャ 177 ラディッツ編

4 8 亀仙人 139 ラディッツ編

5 5 農夫 5 ラディッツ編

1 1 フリーザ 530000 フリーザ編

2 6 ギニュー 120000 フリーザ編

3 7 クリリン 1500 フリーザ編

※実行結果

ラディッツ編で集計

フリーザ編で集計

RANKが別々に振られる

Page 51: Webで役立つRDBの使い方

連番を作る

もっと複雑なランキング

Page 52: Webで役立つRDBの使い方

名前 戦闘力 編フリーザ 530000 フリーザ編フリーザ 10000000 フリーザ編フリーザ 20000000 フリーザ編

悟飯(幼少期) 1307 ラディッツ編クリリン 206 ラディッツ編ヤムチャ 177 ラディッツ編農夫 5 ラディッツ編ギニュー 120000 フリーザ編クリリン 1500 フリーザ編クリリン 0 フリーザ編クリリン 10000 フリーザ編亀仙人 139 ラディッツ編

Page 53: Webで役立つRDBの使い方

ランキングを作る要件

1 戦闘力の降順(DESC) 2 表示はRANKと名前と戦闘力と編 3 編で分ける 4 キャラクターの戦闘力の最大値

Page 54: Webで役立つRDBの使い方

実際のSQL

SELECTrank() OVER ( PARTITION BY "編"

ORDER BY max("戦闘力") DESC

) , "名前", MAX("戦闘力"), "編"

FROM "キャラクター2"

GROUP BY "名前","編";

Page 55: Webで役立つRDBの使い方

実際のSQL

SELECTrank() OVER ( PARTITION BY "編"

ORDER BY max("戦闘力") DESC

) , "名前", MAX("戦闘力"), "編"

FROM "キャラクター2"

GROUP BY "名前","編"; 集約関数を指定する

Page 56: Webで役立つRDBの使い方

実際のSQL

SELECTrank() OVER ( PARTITION BY "編"

ORDER BY max("戦闘力") DESC

) , "名前", MAX("戦闘力"), "編"

FROM "キャラクター2"

GROUP BY "名前","編"; 集約関数を指定する

編ごとの最大戦闘力を指定

Page 57: Webで役立つRDBの使い方

RANK 名前 戦闘力 編

1 悟飯(幼少期) 1307 ラディッツ編

2 クリリン 206 ラディッツ編

3 ヤムチャ 177 ラディッツ編

4 亀仙人 139 ラディッツ編

5 農夫 5 ラディッツ編

1 フリーザ 20000000 フリーザ編

2 ギニュー 120000 フリーザ編

3 クリリン 10000 フリーザ編

※実行結果

Page 58: Webで役立つRDBの使い方

関数 説明row_number() 行番号rank() ランキング (同率で番号を飛ばす)

dense_rank() ランキング (同率で番号を飛ばさない)

percent_rank() ランキング (%で表示) : (rank - 1) / (全行数 - 1)

cume_dist() percent_rank に類似 : (現在の行の位置) / (全行数)ntile(N) ランキング (1..N に分割)

lag(value, offset, default) ソート状態での前の行の値lead(value, offset, default) ソート状態での後の行の値

first_value(value) 最初の値last_value(value) 最後の値nth_value(value, N) N番目の値 (1から数える)

※Window関数で指定できる関数

Page 59: Webで役立つRDBの使い方

連番を作る

PostgreSQLでは 連番を作る関数がある

Page 60: Webで役立つRDBの使い方

連番を作る

generate_series(start, end, step)

Page 61: Webで役立つRDBの使い方

generate_series()

SELECT

generate_series(1, 10),

generate_series(1, 10, 2),

date(now())

+ generate_series(0, 9)::INT AS day

Page 62: Webで役立つRDBの使い方

generate_series()

SELECT

generate_series(1, 10),

generate_series(1, 10, 2),

date(now())

+ generate_series(0, 9)::INT AS day

1から10の連番

Page 63: Webで役立つRDBの使い方

generate_series()

SELECT

generate_series(1, 10),

generate_series(1, 10, 2),

date(now())

+ generate_series(0, 9)::INT AS day

1から10の連番

ステップ数を指定した場合

Page 64: Webで役立つRDBの使い方

generate_series()

SELECT

generate_series(1, 10),

generate_series(1, 10, 2),

date(now())

+ generate_series(0, 9)::INT AS day

1から10の連番

ステップ数を指定した場合

連続した日付を生成

Page 65: Webで役立つRDBの使い方

連番 ステップ指定 日付

1 1 2015-05-30

2 3 2015-05-31

3 5 2015-06-01

4 7 2015-06-02

5 9 2015-06-03

6 1 2015-06-04

7 3 2015-06-05

8 5 2015-06-06

9 7 2015-06-07

10 9 2015-06-08

※実行結果

Page 66: Webで役立つRDBの使い方

連番 ステップ指定 日付

1 1 2015-05-30

2 3 2015-05-31

3 5 2015-06-01

4 7 2015-06-02

5 9 2015-06-03

6 1 2015-06-04

7 3 2015-06-05

8 5 2015-06-06

9 7 2015-06-07

10 9 2015-06-08

※実行結果

endの値を超えたので1に戻る

Page 67: Webで役立つRDBの使い方

連番を作る

generate_series()を使えば

MySQLのような連番も作れる

Page 68: Webで役立つRDBの使い方

あじぇんだ

1 自己紹介 2 連番を作る 3 クエリを減らす 4 まとめ

Page 69: Webで役立つRDBの使い方

クエリを減らす

追加と更新を同時にしたい

Page 70: Webで役立つRDBの使い方

クエリを減らす

追加と更新を同時にしたい ↓

Merge文

Page 71: Webで役立つRDBの使い方

クエリを減らす

残念ながら…

MySQLにもPostgreSQLにも無い

Page 72: Webで役立つRDBの使い方

クエリを減らす

MySQLには ↓

ON DUPLICATE KEY UPDATE

Page 73: Webで役立つRDBの使い方

クエリを減らすON DUPLICATE KEY UPDATE

プライマリーキー制約やユニーク制約が設定されているカラムにデータを追加する際に、既にデータがあれば例外後にUPDATE文を行う

Page 74: Webで役立つRDBの使い方

ON DUPLICATE KEY UPDATE

INSERT users (id, name) SELECT id + 5 AS id, @num := @num + 1 AS name FROM users, (SELECT @num := 0) AS numON DUPLICATE KEY UPDATE name = CONCAT('taketomo', @num := @num + 1)

Page 75: Webで役立つRDBの使い方

ON DUPLICATE KEY UPDATE

INSERT users (id, name) SELECT id + 5 AS id, @num := @num + 1 AS name FROM users, (SELECT @num := 0) AS numON DUPLICATE KEY UPDATE name = CONCAT('taketomo', @num := @num + 1)

既存のIDの+5を指定

Page 76: Webで役立つRDBの使い方

ON DUPLICATE KEY UPDATE

INSERT users (id, name) SELECT id + 5 AS id, @num := @num + 1 AS name FROM users, (SELECT @num := 0) AS numON DUPLICATE KEY UPDATE name = CONCAT('taketomo', @num := @num + 1)

既存のIDの+5を指定

INSERTの場合

Page 77: Webで役立つRDBの使い方

ON DUPLICATE KEY UPDATE

INSERT users (id, name) SELECT id + 5 AS id, @num := @num + 1 AS name FROM users, (SELECT @num := 0) AS numON DUPLICATE KEY UPDATE name = CONCAT('taketomo', @num := @num + 1)

既存のIDの+5を指定

INSERTの場合

UPDATEの場合

Page 78: Webで役立つRDBの使い方

ID 名前 作成日

1 soudai+1 "2015-05-30 06:21:50"2 soudai+2 "2015-05-30 06:21:53"3 soudai+3 "2015-05-30 06:21:54"4 soudai+4 "2015-05-30 06:21:55"5 soudai+5 "2015-05-30 06:21:55"6 taketomo10 "2015-05-30 06:21:56"7 taketomo11 "2015-05-30 06:21:58"8 taketomo12 "2015-05-30 06:21:58"9 taketomo13 "2015-05-30 06:21:59"10 5 "2015-05-30 06:22:05"11 6 "2015-05-30 06:22:05"12 7 "2015-05-30 06:22:05"13 8 "2015-05-30 06:22:05"14 9 "2015-05-30 06:22:05"

※実行結果

Page 79: Webで役立つRDBの使い方

ID 名前 作成日

1 soudai+1 "2015-05-30 06:21:50"2 soudai+2 "2015-05-30 06:21:53"3 soudai+3 "2015-05-30 06:21:54"4 soudai+4 "2015-05-30 06:21:55"5 soudai+5 "2015-05-30 06:21:55"6 taketomo10 "2015-05-30 06:21:56"7 taketomo11 "2015-05-30 06:21:58"8 taketomo12 "2015-05-30 06:21:58"9 taketomo13 "2015-05-30 06:21:59"10 5 "2015-05-30 06:22:05"11 6 "2015-05-30 06:22:05"12 7 "2015-05-30 06:22:05"13 8 "2015-05-30 06:22:05"14 9 "2015-05-30 06:22:05"

※実行結果

IDが衝突したのでUPADTEした

Page 80: Webで役立つRDBの使い方

ID 名前 作成日

1 soudai+1 "2015-05-30 06:21:50"2 soudai+2 "2015-05-30 06:21:53"3 soudai+3 "2015-05-30 06:21:54"4 soudai+4 "2015-05-30 06:21:55"5 soudai+5 "2015-05-30 06:21:55"6 taketomo10 "2015-05-30 06:21:56"7 taketomo11 "2015-05-30 06:21:58"8 taketomo12 "2015-05-30 06:21:58"9 taketomo13 "2015-05-30 06:21:59"10 5 "2015-05-30 06:22:05"11 6 "2015-05-30 06:22:05"12 7 "2015-05-30 06:22:05"13 8 "2015-05-30 06:22:05"14 9 "2015-05-30 06:22:05"

※実行結果

IDが衝突したのでUPADTEした

新規のINSERT

Page 81: Webで役立つRDBの使い方

クエリを減らす

MySQLには ↓

REPLACE文

Page 82: Webで役立つRDBの使い方

クエリを減らすREPLACE文

プライマリーキー制約やユニーク制約が設定されているカラムで既にデータがあれば対象のデータを削除後にINSERT文を行う

Page 83: Webで役立つRDBの使い方

REPLACE

REPLACE users (id, name) SELECT id + 5 AS id, CONCAT('replace', @num := @num + 1) FROM users, (SELECT @num := 0) AS num;

INSERTの条件

既存のIDの+5を指定

Page 84: Webで役立つRDBの使い方

ID 名前 作成日1 soudai+1 "2015-05-30 06:21:50"2 soudai+2 "2015-05-30 06:21:53"3 soudai+3 "2015-05-30 06:21:54"4 soudai+4 "2015-05-30 06:21:55"5 soudai+5 "2015-05-30 06:21:55"6 replace1 "2015-05-30 08:06:59"7 replace2 "2015-05-30 08:06:59"8 replace3 "2015-05-30 08:06:59"9 replace4 "2015-05-30 08:06:59"10 replace5 "2015-05-30 08:06:59"11 replace6 "2015-05-30 08:06:59"12 replace7 "2015-05-30 08:06:59"13 replace8 "2015-05-30 08:06:59"14 replace9 "2015-05-30 08:06:59"15 replace10 "2015-05-30 08:06:59"

※実行結果

Page 85: Webで役立つRDBの使い方

ID 名前 作成日1 soudai+1 "2015-05-30 06:21:50"2 soudai+2 "2015-05-30 06:21:53"3 soudai+3 "2015-05-30 06:21:54"4 soudai+4 "2015-05-30 06:21:55"5 soudai+5 "2015-05-30 06:21:55"6 replace1 "2015-05-30 08:06:59"7 replace2 "2015-05-30 08:06:59"8 replace3 "2015-05-30 08:06:59"9 replace4 "2015-05-30 08:06:59"10 replace5 "2015-05-30 08:06:59"11 replace6 "2015-05-30 08:06:59"12 replace7 "2015-05-30 08:06:59"13 replace8 "2015-05-30 08:06:59"14 replace9 "2015-05-30 08:06:59"15 replace10 "2015-05-30 08:06:59"

※実行結果

IDがかぶっていないので直接 INSERTしている

Page 86: Webで役立つRDBの使い方

ID 名前 作成日1 soudai+1 "2015-05-30 06:21:50"2 soudai+2 "2015-05-30 06:21:53"3 soudai+3 "2015-05-30 06:21:54"4 soudai+4 "2015-05-30 06:21:55"5 soudai+5 "2015-05-30 06:21:55"6 replace1 "2015-05-30 08:06:59"7 replace2 "2015-05-30 08:06:59"8 replace3 "2015-05-30 08:06:59"9 replace4 "2015-05-30 08:06:59"10 replace5 "2015-05-30 08:06:59"11 replace6 "2015-05-30 08:06:59"12 replace7 "2015-05-30 08:06:59"13 replace8 "2015-05-30 08:06:59"14 replace9 "2015-05-30 08:06:59"15 replace10 "2015-05-30 08:06:59"

※実行結果

IDが衝突したのでDELETEして INSERTしている

IDがかぶっていないので直接 INSERTしている

Page 87: Webで役立つRDBの使い方

クエリを減らすREPLACE文

• 構文はINSERTと同じ • 対象は全て削除してから作り直す • AUTO_INCREMENTが変わる • 構文でIDを指定しない場合はIDが振り直し

Page 88: Webで役立つRDBの使い方

クエリを減らすPostgreSQL 9.5

• INSERTの衝突時のUPDATEが実装される(予定 • ON CONFLICT DO NOTHING/UPDATE • Marge文(UPSERT文)は何年も議論が進んでない (現状の実装ではレアケースでクラッシュするらしい) • Marge文はSQL標準なのでいつか実装する(多分

Page 89: Webで役立つRDBの使い方

クエリを減らすPostgreSQL 9.5

• INSERTの衝突時のUPDATEが実装される(予定 • ON CONFLICT DO NOTHING/UPDATE • Marge文(UPSERT文)は何年も議論が進んでない (現状の実装ではレアケースでクラッシュするらしい) • Marge文はSQL標準なのでいつか実装する(多分

Page 90: Webで役立つRDBの使い方

クエリを減らす

PostgreSQLにも便利な機能がある↓

RETURNING句

Page 91: Webで役立つRDBの使い方

クエリを減らすRETURNING句

PostgreSQLの独自拡張で INSERT・UPDATE・DELETE

の結果を返す

Page 92: Webで役立つRDBの使い方

RETURNING

INSERT INTO tmp_log(VALUE)VALUES ('test1') , ('test2') , ('test3')RETURNING *;

Page 93: Webで役立つRDBの使い方

RETURNING

INSERT INTO tmp_log(VALUE)VALUES ('test1') , ('test2') , ('test3')RETURNING *;

通常のINSERTの構文

Page 94: Webで役立つRDBの使い方

RETURNING

INSERT INTO tmp_log(VALUE)VALUES ('test1') , ('test2') , ('test3')RETURNING *;

通常のINSERTの構文

返す戻り値を指定

Page 95: Webで役立つRDBの使い方

ID 名前 作成日

1 test1 "2015-05-30 21:25:18.699022"

2 test2 "2015-05-30 21:25:18.699022"

3 test3 "2015-05-30 21:25:18.699022"

4 test4 "2015-05-30 21:25:18.699022"

5 test5 "2015-05-30 21:25:18.699022"

6 test6 "2015-05-30 21:25:18.699022"

7 test7 "2015-05-30 21:25:18.699022"

※実行結果

Page 96: Webで役立つRDBの使い方

RETURNING句使い方

• INSERTしたレコードのIDの確認が不要 • WHERE句を利用したUPDATE文の対象を取得 • WITH句と組み合わせると戻り値を利用できる • WITH句+RETURNING句でMerge文も出来る

Page 97: Webで役立つRDBの使い方

WITH+RETURNINGWITH base AS ( SELECT * FROM tmp_log), upd AS ( UPDATE tmp_log SET value = base.value || ' update' FROM base WHERE tmp_log.id > 2 RETURNING tmp_log.id)INSERT INTO tmp_log (value) SELECT value || ‘ INSERT’ FROM base AS ins WHERE id NOT IN (SELECT id FROM upd);

Page 98: Webで役立つRDBの使い方

WITH+RETURNINGWITH base AS ( SELECT * FROM tmp_log), upd AS ( UPDATE tmp_log SET value = base.value || ' update' FROM base WHERE tmp_log.id > 2 RETURNING tmp_log.id)INSERT INTO tmp_log (value) SELECT value || ‘INSERT’ FROM base AS ins WHERE id NOT IN (SELECT id FROM upd);

対象のテーブルを指定する

Page 99: Webで役立つRDBの使い方

WITH+RETURNINGWITH base AS ( SELECT * FROM tmp_log), upd AS ( UPDATE tmp_log SET value = base.value || ' update' FROM base WHERE tmp_log.id > 2 RETURNING tmp_log.id)INSERT INTO tmp_log (value) SELECT value || ‘INSERT’ FROM base AS ins WHERE id NOT IN (SELECT id FROM upd);

対象のテーブルを指定する

UPDATEを行う

UPDATEしたIDを返す

Page 100: Webで役立つRDBの使い方

WITH+RETURNINGWITH base AS ( SELECT * FROM tmp_log), upd AS ( UPDATE tmp_log SET value = base.value || ' update' FROM base WHERE tmp_log.id > 2 RETURNING tmp_log.id)INSERT INTO tmp_log (value) SELECT value || ‘INSERT’ FROM base AS ins WHERE id NOT IN (SELECT id FROM upd);

対象のテーブルを指定する

UPDATEを行う

UPDATEしたIDを返すUPDATE以外の結果を

INSERT

Page 101: Webで役立つRDBの使い方

WITH+RETURNING

tmp_log

一時領域

Page 102: Webで役立つRDBの使い方

WITH+RETURNING

base tmp_logWITH

一時領域

Page 103: Webで役立つRDBの使い方

WITH+RETURNING

base tmp_log

一時領域

upd

UPDATE

Page 104: Webで役立つRDBの使い方

WITH+RETURNING

base tmp_log

一時領域

upd

RETURNINGupd

Page 105: Webで役立つRDBの使い方

WITH+RETURNING

base tmp_log

一時領域

updupd

ins

ins

サブクエリ

Page 106: Webで役立つRDBの使い方

WITH+RETURNING

base tmp_log

一時領域

updupd

ins

ins

INSERT

ins

Page 107: Webで役立つRDBの使い方

ID 名前 作成日

1 test1 "2015-05-30 21:41:15.014615"

2 test2 "2015-05-30 21:41:15.014615"

3 test1 update "2015-05-30 21:41:15.014615"

4 test1 update "2015-05-30 21:41:15.014615"

5 test1 update "2015-05-30 21:41:15.014615"

6 test1 update "2015-05-30 21:41:15.014615"

7 test1 update "2015-05-30 21:41:15.014615"

8 test1INSERT "2015-05-30 21:42:32.749261"

9 test2INSERT "2015-05-30 21:42:32.749261"

※実行結果

Page 108: Webで役立つRDBの使い方

あじぇんだ

1 自己紹介 2 連番を作る 3 クエリを減らす 4 まとめ

Page 109: Webで役立つRDBの使い方

まとめ

Page 110: Webで役立つRDBの使い方

まとめ

Webは日々複雑になっている

Page 111: Webで役立つRDBの使い方

まとめ

Webは日々複雑になっている ↓

取り扱うデータも増えている

Page 112: Webで役立つRDBの使い方

まとめ

運用が始まるとデータは変えれない

Page 113: Webで役立つRDBの使い方

まとめ

運用が始まるとデータは変えれない ↓

どんなにコードが綺麗でもデータ構造がダメだとリファクタリングは難しい

Page 114: Webで役立つRDBの使い方

まとめ

データの扱い(SQL)を覚える

Page 115: Webで役立つRDBの使い方

まとめ

SQLを使ってデータを守る

Page 116: Webで役立つRDBの使い方

まとめ

SQLを使ってデータを守る ↓

運用をシンプルにする

Page 117: Webで役立つRDBの使い方

まとめ

データの寿命はコードより長い

Page 118: Webで役立つRDBの使い方

ご静聴ありがとうございました。