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.

削除フラグのはなし

43,135 views

Published on

Published in: Business, Education, Technology

削除フラグのはなし

  1. 1. id name pass is_deleted1 ryu xxx FALSE2 ken xxx FALSE3 honda xxx TRUE
  2. 2. id name pass is_deleted1 ryu xxx FALSE2 ken xxx FALSE3 honda xxx TRUE3 honda xxx FALSE
  3. 3. WHERE is_deleted = falseWHERE is_deleted = falseWHERE is_deleted = false
  4. 4. DELETE FROM users WHERE id = 2;UPDATE user SET is_update = true WHERE id = 2;
  5. 5. id name pass is_deleted1 ryu xxx TRUE2 ryu xxx TRUE3 ryu xxx FALSE4 ryu xxx FALSE
  6. 6. id name pass is_deleted1 ryu xxx TRUE2 ryu xxx TRUE3 ryu xxx FALSE4 ryu xxx FALSE
  7. 7. --CREATE TABLE users ( id SERIAL PRIMARY KEY, name TEXT, pass TEXT, is_deleted BOOL DEFAULT false);--CREATE UNIQUE INDEX users_valid_constraint ON users (name) WHERE NOT is_deleted;
  8. 8. -- テーブルを作成するCREATE TABLE users ( id SERIAL PRIMARY KEY, name TEXT, pass TEXT, is_deleted BOOL DEFAULT false);-- 一意な部分インデックスを張るCREATE UNIQUE INDEX users_valid_constraint ON users (name) WHERE NOT is_deleted;
  9. 9. -- ryuを登録するtestdb=# INSERT INTO users (name, pass, is_deleted)testdb-# VALUES (ryu, xxx, false);INSERT 0 1-- 登録したデータを確認testdb=# SELECT * FROM users; id | name | pass | is_deleted ----+------+------+------------ 1 | ryu | xxx | f(1 row)
  10. 10. -- 更にもう一件重複するryuを登録するtestdb=# INSERT INTO users (name, pass, is_deleted)testdb-# VALUES (ryu, xxx, false);ERROR: duplicate key value violates unique constraint "users_valid_constraint"DETAIL: Key (name)=(ryu) already exists.
  11. 11. -- 削除フラグを立ててryuを削除したことにするtestdb=# UPDATE users SET is_deleted = truetestdb-# WHERE id = 1;UPDATE 1-- ryuが論理削除されたことを確認testdb=# SELECT * FROM users; id | name | pass | is_deleted ----+------+------+------------ 1 | ryu | xxx | t(1 row)
  12. 12. -- ryuは削除されているのでryuを登録するtestdb=# INSERT INTO users (name, pass, is_deleted)testdb-# VALUES (ryu, xxx, false);INSERT 0 1-- 登録したデータを確認するtestdb=# SELECT * FROM users; id | name | pass | is_deleted ----+------+------+------------ 1 | ryu | xxx | t 3 | ryu | xxx | f(2 rows)
  13. 13. -- 削除フラグを戻して削除したryuを復活させるtestdb=# UPDATE users SET is_deleted = falsetestdb-# WHERE id = 1;ERROR: duplicate key value violates unique constraint "users_valid_constraint"DETAIL: Key (name)=(ryu) already exists.
  14. 14. -- 現在のデータを確認するtestdb=# SELECT * FROM users; id | name | pass | is_deleted ----+------+------+------------ 1 | ryu | xxx | t 3 | ryu | xxx | f(2 rows)-- 削除されていない方のryuを論理削除するtestdb=# UPDATE users SET is_deleted = truetestdb-# WHERE id = 3;-- 論理削除されたryuは2件あることを確認testdb=# SELECT * FROM users; id | name | pass | is_deleted ----+------+------+------------ 1 | ryu | xxx | t 3 | ryu | xxx | t(2 rows)
  15. 15. ☓☓
  16. 16. ☓☓
  17. 17. -- ユーザテーブルを作成する -- エントリーテーブルを作成するCREATE TABLE users ( CREATE TABLE entries ( user_id SERIAL NOT NULL, entry_id SERIAL NOT NULL, name TEXT, user_id INTEGER NOT NULL, pass TEXT, event_id INTEGER NOT NULL, PRIMARY KEY(user_id) stat TEXT NOT NULL,); message TEXT, PRIMARY KEY(entry_id),-- イベントテーブルを作成する FOREIGN KEY(user_id)CREATE TABLE events ( REFERENCES users(user_id) event_id SERIAL NOT NULL, ON DELETE CASCADE user_id INTEGER NOT NULL, ON UPDATE CASCADE, name TEXT, FOREIGN KEY(event_id) PRIMARY KEY(event_id), REFERENCES events(event_id) FOREIGN KEY(user_id) ON DELETE CASCADE REFERENCES users(user_id) ON UPDATE CASCADE, ON DELETE CASCADE UNIQUE(user_id, event_id) ON UPDATE CASCADE ););
  18. 18. -- 一意な部分インデックスを張る(IDを利用)CREATE UNIQUE INDEX users_valid_constraint ON users (name) WHERE 0 < user_id;
  19. 19. -- テストデータを投入するINSERT INTO users (name, pass) VALUES (ryu, xxx);INSERT INTO users (name, pass) VALUES (ken, xxx);INSERT INTO events (user_id, name) VALUES (1, 〇〇勉強会);INSERT INTO events (user_id, name) VALUES (1, ××勉強会);INSERT INTO events (user_id, name) VALUES (2, △△勉強会);INSERT INTO entries (event_id, user_id, stat, message) VALUES (1, 1, 参加, いち);INSERT INTO entries (event_id, user_id, stat, message) VALUES (1, 2, 参加, 参加します);INSERT INTO entries (event_id, user_id, stat, message) VALUES (2, 1, キャンセル, ごめんね);INSERT INTO entries (event_id, user_id, stat, message) VALUES (2, 2, 参加, にばん);INSERT INTO entries (event_id, user_id, stat, message) VALUES (3, 2, 参加, よろしく);
  20. 20. -- テストデータを確認するtestdb=# SELECT * FROM users; user_id | name | pass ---------+------+------ 1 | ryu | xxx 2 | ken | xxx(2 rows)testdb=# SELECT * FROM events; event_id | user_id | name ----------+---------+------------ 1 | 1 | 〇〇勉強会 2 | 1 | ××勉強会 3 | 2 | △△勉強会(3 rows)testdb=# SELECT * FROM entries;; entry_id | user_id | event_id | stat | message ----------+---------+----------+------------+------------ 1 | 1 | 1 | 参加 | いち 2 | 2 | 1 | 参加 | 参加します 3 | 1 | 2 | キャンセル | ごめんね 4 | 2 | 2 | 参加 | にばん 5 | 2 | 3 | 参加 | よろしく(5 rows)
  21. 21. -- イベントを論理削除するUPDATE events SET event_id = event_id * -1 WHERE event_id = 1;
  22. 22. -- 参照しているテーブルを確認するtestdb=# SELECT * FROM users; user_id | name | pass ---------+------+------ 1 | ryu | xxx 2 | ken | xxx(2 rows)testdb=# SELECT * FROM events; event_id | user_id | name ----------+---------+------------ 2 | 1 | ××勉強会 3 | 2 | △△勉強会 -1 | 1 | 〇〇勉強会(3 rows)testdb=# SELECT * FROM entries; entry_id | user_id | event_id | stat | message ----------+---------+----------+------------+------------ 3 | 1 | 2 | キャンセル | ごめんね 4 | 2 | 2 | 参加 | にばん 5 | 2 | 3 | 参加 | よろしく 1 | 1 | -1 | 参加 | いち 2 | 2 | -1 | 参加 | 参加します(5 rows)
  23. 23. -- ユーザを論理削除するUPDATE users SET user_id = user_id * -1 WHERE user_id = 2;
  24. 24. -- 参照しているテーブルを確認するtestdb=# SELECT * FROM users; user_id | name | pass ---------+------+------ 1 | ryu | xxx -2 | ken | xxx(2 rows)testdb=# SELECT * FROM events; event_id | user_id | name ----------+---------+------------ 2 | 1 | ××勉強会 -1 | 1 | 〇〇勉強会 3 | -2 | △△勉強会(3 rows)testdb=# SELECT * FROM entries; entry_id | user_id | event_id | stat | message ----------+---------+----------+------------+------------ 3 | 1 | 2 | キャンセル | ごめんね 1 | 1 | -1 | 参加 | いち 4 | -2 | 2 | 参加 | にばん 5 | -2 | 3 | 参加 | よろしく 2 | -2 | -1 | 参加 | 参加します(5 rows)
  25. 25. -- ちなみに、物理削除するとON DELETE CASCADEで連鎖削除されるtestdb=# DELETE FROM users WHERE user_id = 1;DELETE 1testdb=# SELECT * FROM users; user_id | name | pass ---------+------+------ -2 | ken | xxx(1 row)testdb=# SELECT * FROM events; event_id | user_id | name ----------+---------+---------- 3 | -2 | △△勉強会(1 row)testdb=# SELECT * FROM entries; entry_id | user_id | event_id | stat | message ----------+---------+----------+------+---------- 5 | -2 | 3 | 参加 | よろしく(1 row)
  26. 26. -- ユーザテーブルを作成する -- エントリーテーブルを作成するCREATE TABLE users ( CREATE TABLE entries ( user_id SERIAL NOT NULL, entry_id SERIAL NOT NULL, name TEXT, user_id INTEGER NOT NULL, pass TEXT, event_id INTEGER NOT NULL, PRIMARY KEY(user_id) stat TEXT NOT NULL,); message TEXT, PRIMARY KEY(entry_id),-- イベントテーブルを作成する FOREIGN KEY(user_id)CREATE TABLE events ( REFERENCES users(user_id) event_id SERIAL NOT NULL, ON DELETE CASCADE user_id INTEGER NOT NULL, ON UPDATE CASCADE, name TEXT, FOREIGN KEY(event_id) PRIMARY KEY(event_id), REFERENCES events(event_id) FOREIGN KEY(user_id) ON DELETE CASCADE REFERENCES users(user_id) ON UPDATE CASCADE, ON DELETE CASCADE UNIQUE(user_id, event_id) ON UPDATE CASCADE ););
  27. 27. -- 部分インデックスではなくユニークになるCREATE UNIQUE INDEX unq_users_name ON users (name);
  28. 28. -- 削除されたユーザの保存先を作成するCREATE TABLE deleted_users ( user_id SERIAL NOT NULL, name TEXT, pass TEXT);-- 削除されたイベントの保存先を作成するCREATE TABLE deleted_events ( event_id SERIAL NOT NULL, user_id INTEGER NOT NULL, name TEXT);-- 削除されたエントリの保存先を作成するCREATE TABLE deleted_entries ( entry_id SERIAL NOT NULL, user_id INTEGER NOT NULL, event_id INTEGER NOT NULL, stat TEXT NOT NULL, message TEXT);
  29. 29. -- DELETE実行時に実行するFUNCTIONを定義するCREATE OR REPLACE FUNCTION process_deleted() RETURNS TRIGGER AS $$ BEGIN IF (TG_OP = DELETE) THEN EXECUTE INSERT INTO deleted_ || TG_RELNAME || VALUES(($1).*) USING OLD; RETURN OLD; END IF; RETURN NULL; END;$$ LANGUAGE plpgsql;
  30. 30. -- DELETE時に実行するTRIGGERを仕掛けるCREATE TRIGGER trigger_users_deletedAFTER DELETE ON users FOR EACH ROW EXECUTE PROCEDURE process_deleted();CREATE TRIGGER trigger_events_deletedAFTER DELETE ON events FOR EACH ROW EXECUTE PROCEDURE process_deleted();CREATE TRIGGER trigger_entries_deletedAFTER DELETE ON entries FOR EACH ROW EXECUTE PROCEDURE process_deleted();
  31. 31. -- テストデータを投入するINSERT INTO users (name, pass) VALUES (ryu, xxx);INSERT INTO users (name, pass) VALUES (ken, xxx);INSERT INTO events (user_id, name) VALUES (1, 〇〇勉強会);INSERT INTO events (user_id, name) VALUES (1, ××勉強会);INSERT INTO events (user_id, name) VALUES (2, △△勉強会);INSERT INTO entries (event_id, user_id, stat, message) VALUES (1, 1, 参加, いち);INSERT INTO entries (event_id, user_id, stat, message) VALUES (1, 2, 参加, 参加します);INSERT INTO entries (event_id, user_id, stat, message) VALUES (2, 1, キャンセル, ごめんね);INSERT INTO entries (event_id, user_id, stat, message) VALUES (2, 2, 参加, にばん);INSERT INTO entries (event_id, user_id, stat, message) VALUES (3, 2, 参加, よろしく);
  32. 32. -- テストデータを確認するtestdb=# SELECT * FROM users; user_id | name | pass ---------+------+------ 1 | ryu | xxx 2 | ken | xxx(2 rows)testdb=# SELECT * FROM events; event_id | user_id | name ----------+---------+------------ 1 | 1 | 〇〇勉強会 2 | 1 | ××勉強会 3 | 2 | △△勉強会(3 rows)testdb=# SELECT * FROM entries;; entry_id | user_id | event_id | stat | message ----------+---------+----------+------------+------------ 1 | 1 | 1 | 参加 | いち 2 | 2 | 1 | 参加 | 参加します 3 | 1 | 2 | キャンセル | ごめんね 4 | 2 | 2 | 参加 | にばん 5 | 2 | 3 | 参加 | よろしく(5 rows)
  33. 33. -- 削除されたデータの保存先は空testdb=# SELECT * FROM deleted_users; user_id | name | pass ---------+------+------(0 rows)testdb=# SELECT * FROM deleted_events; event_id | user_id | name ----------+---------+------(0 rows)testdb=# SELECT * FROM deleted_entries; entry_id | user_id | event_id | stat | message ----------+---------+----------+------+---------(0 rows)
  34. 34. -- ユーザを削除してみるDELETE FROM users WHERE user_id = 1;
  35. 35. -- 他の関連するレコードも連鎖的に削除されているtestdb2=# SELECT * FROM users; user_id | name | pass ---------+------+------ 2 | ken | xxx(1 row)testdb2=# SELECT * FROM events; event_id | user_id | name ----------+---------+---------- 3 | 2 | △△勉強会(1 row)testdb2=# SELECT * FROM entries; entry_id | user_id | event_id | stat | message ----------+---------+----------+------+---------- 5 | 2 | 3 | 参加 | よろしく(1 row)
  36. 36. -- 連鎖的に削除されたレコードは保存用のテーブルに退避されているtestdb2=# SELECT * FROM deleted_users; user_id | name | pass ---------+------+------ 1 | ryu | xxx(1 row)testdb2=# SELECT * FROM deleted_events; event_id | user_id | name ----------+---------+------------ 1 | 1 | 〇〇勉強会 2 | 1 | ××勉強会(2 rows)testdb2=# SELECT * FROM deleted_entries; entry_id | user_id | event_id | stat | message ----------+---------+----------+------------+------------ 1 | 1 | 1 | 参加 | いち 3 | 1 | 2 | キャンセル | ごめんね 2 | 2 | 1 | 参加 | 参加します 4 | 2 | 2 | 参加 | にばん(4 rows)
  37. 37. CREATE TABLE emp ( empname text NOT NULL, salary integer);CREATE TABLE emp_audit( operation char(1) NOT NULL, stamp timestamp NOT NULL, userid text NOT NULL, empname text NOT NULL, salary integer);CREATE OR REPLACE FUNCTION process_emp_audit() RETURNS TRIGGER AS $emp_audit$ BEGIN -- -- Create a row in emp_audit to reflect the operation performed on emp, -- make use of the special variable TG_OP to work out the operation. -- IF (TG_OP = DELETE) THEN INSERT INTO emp_audit SELECT D, now(), user, OLD.*; RETURN OLD; ELSIF (TG_OP = UPDATE) THEN INSERT INTO emp_audit SELECT U, now(), user, NEW.*; RETURN NEW; ELSIF (TG_OP = INSERT) THEN INSERT INTO emp_audit SELECT I, now(), user, NEW.*; RETURN NEW; END IF; RETURN NULL; -- result is ignored since this is an AFTER trigger END;$emp_audit$ LANGUAGE plpgsql;CREATE TRIGGER emp_auditAFTER INSERT OR UPDATE OR DELETE ON emp FOR EACH ROW EXECUTE PROCEDURE process_emp_audit();

×