Your SlideShare is downloading. ×
0
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Webで役立つRDBの使い方
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Webで役立つRDBの使い方

146

Published on

第九回中国地方DB勉強会 in 米子の資料です

第九回中国地方DB勉強会 in 米子の資料です

Published in: Data & Analytics
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
146
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Webで役立つRDBの使い方 第九回 中国地方DB勉強会 in 米子
  • 2. What is it? データベースは何を基準に選んでますか?
  • 3. What is it? RDBを制する者は データ層を制する と言っても過言ではありません
  • 4. What is it? 今日は アプリを書く上で便利な事 をご紹介します
  • 5. What is it? ただし インデックスやDB設計 の話は今日はしません
  • 6. What is it? 主にSQLの話です
  • 7. What is it? MySQLやPostgreSQLを使う人の 今日から使える便利な知識(SQL) を持ち帰って活用してください
  • 8. あじぇんだ 1 自己紹介 2 連番を作る 3 クエリを減らす 4 まとめ
  • 9. あじぇんだ 1 自己紹介 2 連番を作る 3 クエリを減らす 4 まとめ
  • 10. 自己紹介 名前:曽根 壮大(そね たけとも) 年齢:30歳(三人の子供がいます) 職業:Webエンジニア 所属:日本PostgreSQLユーザ会    中国支部 支部長   技術的にはLL系言語とかRDBが好きです
  • 11. あじぇんだ 1 自己紹介 2 連番を作る 3 クエリを減らす 4 まとめ
  • 12. 連番を作る 検索結果に合わせて連番を作る
  • 13. ID 名前 戦闘力 編 1 フリーザ 530000 フリーザ編 2 悟飯(幼少期) 1307 ラディッツ編 3 クリリン 206 ラディッツ編 4 ヤムチャ 177 ラディッツ編 5 農夫 5 ラディッツ編 6 ギニュー 120000 フリーザ編 7 クリリン 1500 フリーザ編 8 亀仙人 139 ラディッツ編 ※実務では編は正規化するべき
  • 14. 連番を作る MySQLの場合
  • 15. 連番を作る MySQLの場合 ↓ SQLの中で変数が使える
  • 16. MySQLの場合 SET @num := 0; SELECT (@num := @num + 1) AS serial, キャラクター.* FROM キャラクター ORDER BY 戦闘力 DESC;
  • 17. MySQLの場合 SET @num := 0; SELECT (@num := @num + 1) AS serial, キャラクター.* FROM キャラクター ORDER BY 戦闘力 DESC; 変数宣言
  • 18. MySQLの場合 SET @num := 0; SELECT (@num := @num + 1) AS serial, キャラクター.* FROM キャラクター ORDER BY 戦闘力 DESC; 変数宣言 変数をインクリメントしながら表示
  • 19. MySQLの場合 SELECT (@num := @num + 1) AS serial, キャラクター.* FROM キャラクター, (SELECT @num := 0 ) AS base ORDER BY 戦闘力 DESC;
  • 20. MySQLの場合 SELECT (@num := @num + 1) AS serial, キャラクター.* FROM キャラクター, (SELECT @num := 0 ) AS base ORDER BY 戦闘力 DESC; 変数宣言をテーブルとして行い、 JOINすることで1回のクエリにする
  • 21. 連番 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 ラディッツ編 ※実行結果
  • 22. 連番を作る 他の変数宣言の使い方
  • 23. MySQLの場合 SET sql_mode = 'PIPES_AS_CONCAT'; SET @num := 1; INSERT INTO users (name) VALUES ( 'soudai+' || (@num := @num + 1) );
  • 24. MySQLの場合 SET sql_mode = 'PIPES_AS_CONCAT'; SET @num := 1; INSERT INTO users (name) VALUES ( 'soudai+' || (@num := @num + 1) ); 文字結合を¦¦で出来るようにモード変更
  • 25. MySQLの場合 SET sql_mode = 'PIPES_AS_CONCAT'; SET @num := 1; INSERT INTO users (name) VALUES ( 'soudai+' || (@num := @num + 1) ); INSERTを実行するたびに nameが変わる 文字結合を¦¦で出来るようにモード変更
  • 26. 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" ※実行結果
  • 27. MySQLの変数宣言 その他の使い方
  • 28. MySQLの変数宣言 その他の使い方 1 帳簿などで連続した日付を作る
  • 29. MySQLの変数宣言 その他の使い方 1 帳簿などで連続した日付を作る 2 テストデータの投入
  • 30. MySQLの変数宣言 その他の使い方 1 帳簿などで連続した日付を作る 2 テストデータの投入 3 一時的にデータを保持をする
  • 31. MySQLの変数宣言 その他の使い方 1 帳簿などで連続した日付を作る 2 テストデータの投入 3 一時的にデータを保持をする
  • 32. MySQLの変数宣言 注意点 変数展開は 「いつ実施されるか定まってない」
  • 33. MySQLの変数宣言 注意点 JOINやサブクエリは 先にselect_listが評価される ↓ SELECT @num = @num+1 の+1が行われない
  • 34. MySQLの変数宣言 注意点 JOINやサブクエリは 先にselect_listが評価される ↓ SELECT @num = @num+1 の+1が行われない 対象の列でORDER BYとかしてるとハマる (というかハマった)
  • 35. 連番を作る PostgreSQLの場合
  • 36. 連番を作る PostgreSQLの場合 ↓ SQL内での変数宣言が無い
  • 37. 連番を作る PostgreSQLの場合 ↓ Window関数を使う
  • 38. 連番を作る ウィンドウ関数 ウィンドウ関数は現在の行に何らの 関係するテーブル行の一纏まり全般 の計算を行う。
  • 39. PostgreSQLの場合 SELECT row_number() OVER( ORDER BY 戦闘力 DESC ) AS serial, * FROM キャラクター;
  • 40. PostgreSQLの場合 SELECT row_number() OVER( ORDER BY 戦闘力 DESC ) AS serial, * FROM キャラクター; 行番号を振る
  • 41. PostgreSQLの場合 SELECT row_number() OVER( ORDER BY 戦闘力 DESC ) AS serial, * FROM キャラクター; 行番号を振る 戦闘力で並べる
  • 42. 連番 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 ラディッツ編 ※実行結果
  • 43. 連番 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と同じ結果
  • 44. 連番を作る 区分ごとのランキングも作れる
  • 45. PostgreSQLの場合 SELECT rank() OVER ( PARTITION BY "編" ORDER BY "戦闘力" DESC ) , * FROM "キャラクター";
  • 46. PostgreSQLの場合 SELECT rank() OVER ( PARTITION BY "編" ORDER BY "戦闘力" DESC ) , * FROM "キャラクター"; 区分を指定する
  • 47. PostgreSQLの場合 SELECT rank() OVER ( PARTITION BY "編" ORDER BY "戦闘力" DESC ) , * FROM "キャラクター"; 区分ごとのランキング 区分を指定する
  • 48. 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 フリーザ編 ※実行結果
  • 49. 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 フリーザ編 ※実行結果 ラディッツ編で集計 フリーザ編で集計
  • 50. 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が別々に振られる
  • 51. 連番を作る もっと複雑なランキング
  • 52. 名前 戦闘力 編 フリーザ 530000 フリーザ編 フリーザ 10000000 フリーザ編 フリーザ 20000000 フリーザ編 悟飯(幼少期) 1307 ラディッツ編 クリリン 206 ラディッツ編 ヤムチャ 177 ラディッツ編 農夫 5 ラディッツ編 ギニュー 120000 フリーザ編 クリリン 1500 フリーザ編 クリリン 0 フリーザ編 クリリン 10000 フリーザ編 亀仙人 139 ラディッツ編
  • 53. ランキングを作る 要件 1 戦闘力の降順(DESC) 2 表示はRANKと名前と戦闘力と編 3 編で分ける 4 キャラクターの戦闘力の最大値
  • 54. 実際のSQL SELECT rank() OVER ( PARTITION BY "編" ORDER BY max("戦闘力") DESC ) , "名前", MAX("戦闘力"), "編" FROM "キャラクター2" GROUP BY "名前","編";
  • 55. 実際のSQL SELECT rank() OVER ( PARTITION BY "編" ORDER BY max("戦闘力") DESC ) , "名前", MAX("戦闘力"), "編" FROM "キャラクター2" GROUP BY "名前","編"; 集約関数を指定する
  • 56. 実際のSQL SELECT rank() OVER ( PARTITION BY "編" ORDER BY max("戦闘力") DESC ) , "名前", MAX("戦闘力"), "編" FROM "キャラクター2" GROUP BY "名前","編"; 集約関数を指定する 編ごとの最大戦闘力を指定
  • 57. RANK 名前 戦闘力 編 1 悟飯(幼少期) 1307 ラディッツ編 2 クリリン 206 ラディッツ編 3 ヤムチャ 177 ラディッツ編 4 亀仙人 139 ラディッツ編 5 農夫 5 ラディッツ編 1 フリーザ 20000000 フリーザ編 2 ギニュー 120000 フリーザ編 3 クリリン 10000 フリーザ編 ※実行結果
  • 58. 関数 説明 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関数で指定できる関数
  • 59. 連番を作る PostgreSQLでは 連番を作る関数がある
  • 60. 連番を作る generate_series(start, end, step)
  • 61. generate_series() SELECT generate_series(1, 10), generate_series(1, 10, 2), date(now()) + generate_series(0, 9)::INT AS day
  • 62. generate_series() SELECT generate_series(1, 10), generate_series(1, 10, 2), date(now()) + generate_series(0, 9)::INT AS day 1から10の連番
  • 63. generate_series() SELECT generate_series(1, 10), generate_series(1, 10, 2), date(now()) + generate_series(0, 9)::INT AS day 1から10の連番 ステップ数を指定した場合
  • 64. generate_series() SELECT generate_series(1, 10), generate_series(1, 10, 2), date(now()) + generate_series(0, 9)::INT AS day 1から10の連番 ステップ数を指定した場合 連続した日付を生成
  • 65. 連番 ステップ指定 日付 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 ※実行結果
  • 66. 連番 ステップ指定 日付 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に戻る
  • 67. 連番を作る generate_series()を使えば MySQLのような連番も作れる
  • 68. あじぇんだ 1 自己紹介 2 連番を作る 3 クエリを減らす 4 まとめ
  • 69. クエリを減らす 追加と更新を同時にしたい
  • 70. クエリを減らす 追加と更新を同時にしたい ↓ Merge文
  • 71. クエリを減らす 残念ながら… MySQLにもPostgreSQLにも無い
  • 72. クエリを減らす MySQLには ↓ ON DUPLICATE KEY UPDATE
  • 73. クエリを減らす ON DUPLICATE KEY UPDATE プライマリーキー制約やユニーク制 約が設定されているカラムにデータ を追加する際に、既にデータがあれ ば例外後にUPDATE文を行う
  • 74. ON DUPLICATE KEY UPDATE INSERT users (id, name) SELECT id + 5 AS id, @num := @num + 1 AS name FROM users, (SELECT @num := 0) AS num ON DUPLICATE KEY UPDATE name = CONCAT('taketomo', @num := @num + 1)
  • 75. ON DUPLICATE KEY UPDATE INSERT users (id, name) SELECT id + 5 AS id, @num := @num + 1 AS name FROM users, (SELECT @num := 0) AS num ON DUPLICATE KEY UPDATE name = CONCAT('taketomo', @num := @num + 1) 既存のIDの+5を指定
  • 76. ON DUPLICATE KEY UPDATE INSERT users (id, name) SELECT id + 5 AS id, @num := @num + 1 AS name FROM users, (SELECT @num := 0) AS num ON DUPLICATE KEY UPDATE name = CONCAT('taketomo', @num := @num + 1) 既存のIDの+5を指定 INSERTの場合
  • 77. ON DUPLICATE KEY UPDATE INSERT users (id, name) SELECT id + 5 AS id, @num := @num + 1 AS name FROM users, (SELECT @num := 0) AS num ON DUPLICATE KEY UPDATE name = CONCAT('taketomo', @num := @num + 1) 既存のIDの+5を指定 INSERTの場合 UPDATEの場合
  • 78. 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" ※実行結果
  • 79. 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した
  • 80. 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
  • 81. クエリを減らす MySQLには ↓ REPLACE文
  • 82. クエリを減らす REPLACE文 プライマリーキー制約やユニーク制 約が設定されているカラムで既にデー タがあれば対象のデータを削除後に INSERT文を行う
  • 83. 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を指定
  • 84. 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" ※実行結果
  • 85. 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している
  • 86. 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している
  • 87. クエリを減らす REPLACE文 • 構文はINSERTと同じ • 対象は全て削除してから作り直す • AUTO_INCREMENTが変わる • 構文でIDを指定しない場合はIDが振り直し
  • 88. クエリを減らす PostgreSQL 9.5 • INSERTの衝突時のUPDATEが実装される(予定 • ON CONFLICT DO NOTHING/UPDATE • Marge文(UPSERT文)は何年も議論が進んでない (現状の実装ではレアケースでクラッシュするらしい) • Marge文はSQL標準なのでいつか実装する(多分
  • 89. クエリを減らす PostgreSQL 9.5 • INSERTの衝突時のUPDATEが実装される(予定 • ON CONFLICT DO NOTHING/UPDATE • Marge文(UPSERT文)は何年も議論が進んでない (現状の実装ではレアケースでクラッシュするらしい) • Marge文はSQL標準なのでいつか実装する(多分
  • 90. クエリを減らす PostgreSQLにも便利な機能がある ↓ RETURNING句
  • 91. クエリを減らす RETURNING句 PostgreSQLの独自拡張で INSERT・UPDATE・DELETE の結果を返す
  • 92. RETURNING INSERT INTO tmp_log (VALUE) VALUES ('test1') , ('test2') , ('test3') RETURNING *;
  • 93. RETURNING INSERT INTO tmp_log (VALUE) VALUES ('test1') , ('test2') , ('test3') RETURNING *; 通常のINSERTの構文
  • 94. RETURNING INSERT INTO tmp_log (VALUE) VALUES ('test1') , ('test2') , ('test3') RETURNING *; 通常のINSERTの構文 返す戻り値を指定
  • 95. 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" ※実行結果
  • 96. RETURNING句 使い方 • INSERTしたレコードのIDの確認が不要 • WHERE句を利用したUPDATE文の対象を取得 • WITH句と組み合わせると戻り値を利用できる • WITH句+RETURNING句でMerge文も出来る
  • 97. WITH+RETURNING WITH 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);
  • 98. WITH+RETURNING WITH 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); 対象のテーブルを指定する
  • 99. WITH+RETURNING WITH 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を返す
  • 100. WITH+RETURNING WITH 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
  • 101. WITH+RETURNING tmp_log 一時領域
  • 102. WITH+RETURNING base tmp_log WITH 一時領域
  • 103. WITH+RETURNING base tmp_log 一時領域 upd UPDATE
  • 104. WITH+RETURNING base tmp_log 一時領域 upd RETURNING upd
  • 105. WITH+RETURNING base tmp_log 一時領域 updupd ins ins サブクエリ
  • 106. WITH+RETURNING base tmp_log 一時領域 updupd ins ins INSERT ins
  • 107. 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" ※実行結果
  • 108. あじぇんだ 1 自己紹介 2 連番を作る 3 クエリを減らす 4 まとめ
  • 109. まとめ
  • 110. まとめ Webは日々複雑になっている
  • 111. まとめ Webは日々複雑になっている ↓ 取り扱うデータも増えている
  • 112. まとめ 運用が始まるとデータは変えれない
  • 113. まとめ 運用が始まるとデータは変えれない ↓ どんなにコードが綺麗でもデータ構造 がダメだとリファクタリングは難しい
  • 114. まとめ データの扱い(SQL)を覚える
  • 115. まとめ SQLを使ってデータを守る
  • 116. まとめ SQLを使ってデータを守る ↓ 運用をシンプルにする
  • 117. まとめ データの寿命はコードより長い
  • 118. ご静聴ありがとうございました。

×