Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Webで役立つRDBの使い方

6,493 views

Published on

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

Published in: Data & Analytics

Webで役立つRDBの使い方

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

×