Your SlideShare is downloading. ×
削除フラグのはなし
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

削除フラグのはなし

37,800
views

Published on

Published in: Business, Education, Technology

2 Comments
92 Likes
Statistics
Notes
No Downloads
Views
Total Views
37,800
On Slideshare
0
From Embeds
0
Number of Embeds
9
Actions
Shares
0
Downloads
207
Comments
2
Likes
92
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. id name pass is_deleted1 ryu xxx FALSE2 ken xxx FALSE3 honda xxx TRUE
  • 2. id name pass is_deleted1 ryu xxx FALSE2 ken xxx FALSE3 honda xxx TRUE3 honda xxx FALSE
  • 3. WHERE is_deleted = falseWHERE is_deleted = falseWHERE is_deleted = false
  • 4. DELETE FROM users WHERE id = 2;UPDATE user SET is_update = true WHERE id = 2;
  • 5. id name pass is_deleted1 ryu xxx TRUE2 ryu xxx TRUE3 ryu xxx FALSE4 ryu xxx FALSE
  • 6. id name pass is_deleted1 ryu xxx TRUE2 ryu xxx TRUE3 ryu xxx FALSE4 ryu xxx FALSE
  • 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. -- テーブルを作成する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. -- 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. -- 更にもう一件重複する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. -- 削除フラグを立てて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. -- 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. -- 削除フラグを戻して削除した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. -- 現在のデータを確認する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. ☓☓
  • 16. ☓☓
  • 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. -- 一意な部分インデックスを張る(IDを利用)CREATE UNIQUE INDEX users_valid_constraint ON users (name) WHERE 0 < user_id;
  • 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. -- テストデータを確認する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. -- イベントを論理削除するUPDATE events SET event_id = event_id * -1 WHERE event_id = 1;
  • 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. -- ユーザを論理削除するUPDATE users SET user_id = user_id * -1 WHERE user_id = 2;
  • 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. -- ちなみに、物理削除すると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. -- ユーザテーブルを作成する -- エントリーテーブルを作成する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. -- 部分インデックスではなくユニークになるCREATE UNIQUE INDEX unq_users_name ON users (name);
  • 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. -- 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. -- 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. -- テストデータを投入する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. -- テストデータを確認する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. -- 削除されたデータの保存先は空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. -- ユーザを削除してみるDELETE FROM users WHERE user_id = 1;
  • 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. -- 連鎖的に削除されたレコードは保存用のテーブルに退避されている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. 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();