SlideShare une entreprise Scribd logo
1  sur  83
Télécharger pour lire hors ligne
id   name    pass   is_deleted
1     ryu    xxx     FALSE
2     ken    xxx     FALSE
3    honda   xxx      TRUE
id   name    pass   is_deleted
1     ryu    xxx     FALSE
2     ken    xxx     FALSE
3    honda   xxx      TRUE



3    honda   xxx     FALSE
WHERE is_deleted = false
WHERE is_deleted = false
WHERE is_deleted = false
DELETE FROM users WHERE id = 2;
UPDATE user SET is_update = true WHERE id = 2;
id   name   pass   is_deleted
1    ryu    xxx      TRUE
2    ryu    xxx      TRUE
3    ryu    xxx     FALSE
4    ryu    xxx     FALSE
id   name   pass   is_deleted
1    ryu    xxx      TRUE
2    ryu    xxx      TRUE
3    ryu    xxx     FALSE
4    ryu    xxx     FALSE
--
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;
--	 テーブルを作成する
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;
--	 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)
--	 更にもう一件重複する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.
--	 削除フラグを立ててryuを削除したことにする
testdb=#	 UPDATE	 users	 SET	 is_deleted	 =	 true
testdb-#	 WHERE	 id	 =	 1;
UPDATE	 1

--	 ryuが論理削除されたことを確認
testdb=#	 SELECT	 *	 FROM	 users;
	 id	 |	 name	 |	 pass	 |	 is_deleted	 
----+------+------+------------
	 	 1	 |	 ryu	 	 |	 xxx	 	 |	 t
(1	 row)
--	 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)
--	 削除フラグを戻して削除したryuを復活させる
testdb=#	 UPDATE	 users	 SET	 is_deleted	 =	 false
testdb-#	 WHERE	 id	 =	 1;
ERROR:	 	 duplicate	 key	 value	 violates	 unique	 constraint	 
"users_valid_constraint"
DETAIL:	 	 Key	 (name)=(ryu)	 already	 exists.
--	 現在のデータを確認する
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	 =	 true
testdb-#	 WHERE	 id	 =	 3;

--	 論理削除されたryuは2件あることを確認
testdb=#	 SELECT	 *	 FROM	 users;
	 id	 |	 name	 |	 pass	 |	 is_deleted	 
----+------+------+------------
	 	 1	 |	 ryu	 	 |	 xxx	 	 |	 t
	 	 3	 |	 ryu	 	 |	 xxx	 	 |	 t
(2	 rows)
☓☓
☓☓
--	 ユーザテーブルを作成する                     --	 エントリーテーブルを作成する
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      );
);
--	 一意な部分インデックスを張る(IDを利用)
CREATE	 UNIQUE	 INDEX	 users_valid_constraint
	 	 	 	 ON	 users	 (name)	 WHERE	 0	 <	 user_id;
--	 テストデータを投入する
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,	 '参加',	 'よろしく');
--	 テストデータを確認する
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)
--	 イベントを論理削除する
UPDATE	 events	 SET	 event_id	 =	 event_id	 *	 -1	 WHERE	 event_id	 =	 1;
--	 参照しているテーブルを確認する
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)
--	 ユーザを論理削除する
UPDATE	 users	 SET	 user_id	 =	 user_id	 *	 -1	 WHERE	 user_id	 =	 2;
--	 参照しているテーブルを確認する
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)
--	 ちなみに、物理削除するとON	 DELETE	 CASCADEで連鎖削除される
testdb=#	 DELETE	 FROM	 users	 WHERE	 user_id	 =	 1;
DELETE	 1

testdb=#	 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)
--	 ユーザテーブルを作成する                     --	 エントリーテーブルを作成する
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      );
);
--	 部分インデックスではなくユニークになる
CREATE	 UNIQUE	 INDEX	 unq_users_name	 ON	 users	 (name);
--	 削除されたユーザの保存先を作成する
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
);
--	 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;
--	 DELETE時に実行するTRIGGERを仕掛ける
CREATE	 TRIGGER	 trigger_users_deleted
AFTER	 DELETE	 ON	 users
	 	 	 	 FOR	 EACH	 ROW	 EXECUTE	 PROCEDURE	 process_deleted();

CREATE	 TRIGGER	 trigger_events_deleted
AFTER	 DELETE	 ON	 events
	 	 	 	 FOR	 EACH	 ROW	 EXECUTE	 PROCEDURE	 process_deleted();

CREATE	 TRIGGER	 trigger_entries_deleted
AFTER	 DELETE	 ON	 entries
	 	 	 	 FOR	 EACH	 ROW	 EXECUTE	 PROCEDURE	 process_deleted();
--	 テストデータを投入する
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,	 '参加',	 'よろしく');
--	 テストデータを確認する
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)
--	 削除されたデータの保存先は空
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)
--	 ユーザを削除してみる
DELETE	 FROM	 users	 WHERE	 user_id	 =	 1;
--	 他の関連するレコードも連鎖的に削除されている
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)
--	 連鎖的に削除されたレコードは保存用のテーブルに退避されている
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)
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_audit
AFTER	 INSERT	 OR	 UPDATE	 OR	 DELETE	 ON	 emp
	 	 	 	 FOR	 EACH	 ROW	 EXECUTE	 PROCEDURE	 process_emp_audit();

Contenu connexe

Tendances

Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Ryosuke Uchitate
 

Tendances (20)

PostgreSQLアーキテクチャ入門(INSIGHT OUT 2011)
PostgreSQLアーキテクチャ入門(INSIGHT OUT 2011)PostgreSQLアーキテクチャ入門(INSIGHT OUT 2011)
PostgreSQLアーキテクチャ入門(INSIGHT OUT 2011)
 
アーキテクチャから理解するPostgreSQLのレプリケーション
アーキテクチャから理解するPostgreSQLのレプリケーションアーキテクチャから理解するPostgreSQLのレプリケーション
アーキテクチャから理解するPostgreSQLのレプリケーション
 
なかったらINSERTしたいし、あるならロック取りたいやん?
なかったらINSERTしたいし、あるならロック取りたいやん?なかったらINSERTしたいし、あるならロック取りたいやん?
なかったらINSERTしたいし、あるならロック取りたいやん?
 
MySQLバックアップの基本
MySQLバックアップの基本MySQLバックアップの基本
MySQLバックアップの基本
 
MySQLアーキテクチャ図解講座
MySQLアーキテクチャ図解講座MySQLアーキテクチャ図解講座
MySQLアーキテクチャ図解講座
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
 
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
 
What's New in MySQL 5.7 Optimizer @MySQL User Conference Tokyo 2015
What's New in MySQL 5.7 Optimizer @MySQL User Conference Tokyo 2015What's New in MySQL 5.7 Optimizer @MySQL User Conference Tokyo 2015
What's New in MySQL 5.7 Optimizer @MySQL User Conference Tokyo 2015
 
Where狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキーWhere狙いのキー、order by狙いのキー
Where狙いのキー、order by狙いのキー
 
あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界あなたの知らないPostgreSQL監視の世界
あなたの知らないPostgreSQL監視の世界
 
NTT DATA と PostgreSQL が挑んだ総力戦
NTT DATA と PostgreSQL が挑んだ総力戦NTT DATA と PostgreSQL が挑んだ総力戦
NTT DATA と PostgreSQL が挑んだ総力戦
 
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
 
押さえておきたい、PostgreSQL 13 の新機能!!(Open Source Conference 2021 Online/Hokkaido 発表資料)
押さえておきたい、PostgreSQL 13 の新機能!!(Open Source Conference 2021 Online/Hokkaido 発表資料)押さえておきたい、PostgreSQL 13 の新機能!!(Open Source Conference 2021 Online/Hokkaido 発表資料)
押さえておきたい、PostgreSQL 13 の新機能!!(Open Source Conference 2021 Online/Hokkaido 発表資料)
 
基礎からのOAuth 2.0とSpring Security 5.1による実装
基礎からのOAuth 2.0とSpring Security 5.1による実装基礎からのOAuth 2.0とSpring Security 5.1による実装
基礎からのOAuth 2.0とSpring Security 5.1による実装
 
EDB Postgres Vision 2019
EDB Postgres Vision 2019 EDB Postgres Vision 2019
EDB Postgres Vision 2019
 
PostgreSQL 15 開発最新情報
PostgreSQL 15 開発最新情報PostgreSQL 15 開発最新情報
PostgreSQL 15 開発最新情報
 
PostgreSQLの関数属性を知ろう
PostgreSQLの関数属性を知ろうPostgreSQLの関数属性を知ろう
PostgreSQLの関数属性を知ろう
 
Zabbix最新情報 ~Zabbix 6.0に向けて~ @OSC2021 Online/Fall
Zabbix最新情報 ~Zabbix 6.0に向けて~ @OSC2021 Online/FallZabbix最新情報 ~Zabbix 6.0に向けて~ @OSC2021 Online/Fall
Zabbix最新情報 ~Zabbix 6.0に向けて~ @OSC2021 Online/Fall
 
基本に戻ってInnoDBの話をします
基本に戻ってInnoDBの話をします基本に戻ってInnoDBの話をします
基本に戻ってInnoDBの話をします
 
Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsug
 

En vedette

Layout analyzerでのgroovyの利用について
Layout analyzerでのgroovyの利用についてLayout analyzerでのgroovyの利用について
Layout analyzerでのgroovyの利用について
kimukou_26 Kimukou
 
ソフトウェアパッケージベンダーのためのクラウドソリューション「SQL Anywhere OnDemand Edition」
ソフトウェアパッケージベンダーのためのクラウドソリューション「SQL Anywhere OnDemand Edition」ソフトウェアパッケージベンダーのためのクラウドソリューション「SQL Anywhere OnDemand Edition」
ソフトウェアパッケージベンダーのためのクラウドソリューション「SQL Anywhere OnDemand Edition」
nisobe58
 
ngServer and-collaboratived-development-between-san-francisco-and-tokyo
ngServer and-collaboratived-development-between-san-francisco-and-tokyongServer and-collaboratived-development-between-san-francisco-and-tokyo
ngServer and-collaboratived-development-between-san-francisco-and-tokyo
Satoshi Tanaka
 
17 E-5 震災とHackとクラウドと 亀渕分
17 E-5 震災とHackとクラウドと 亀渕分17 E-5 震災とHackとクラウドと 亀渕分
17 E-5 震災とHackとクラウドと 亀渕分
Keiji Kamebuchi
 
ngGoBuilder and collaborative development between San Francisco and Tokyo
ngGoBuilder and collaborative development between San Francisco and TokyongGoBuilder and collaborative development between San Francisco and Tokyo
ngGoBuilder and collaborative development between San Francisco and Tokyo
notolab
 
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (後編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (後編)大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (後編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (後編)
Yuuki Namikawa
 
【17-E-3】 オンライン機械学習で実現する大規模データ処理
【17-E-3】 オンライン機械学習で実現する大規模データ処理【17-E-3】 オンライン機械学習で実現する大規模データ処理
【17-E-3】 オンライン機械学習で実現する大規模データ処理
Developers Summit
 
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)
Akihiro Kuwano
 
17 A QuíMica Da Pele
17 A QuíMica Da Pele17 A QuíMica Da Pele
17 A QuíMica Da Pele
Claudia Lage
 

En vedette (17)

SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
Layout analyzerでのgroovyの利用について
Layout analyzerでのgroovyの利用についてLayout analyzerでのgroovyの利用について
Layout analyzerでのgroovyの利用について
 
Building scalablewebapps
Building scalablewebappsBuilding scalablewebapps
Building scalablewebapps
 
ソフトウェアパッケージベンダーのためのクラウドソリューション「SQL Anywhere OnDemand Edition」
ソフトウェアパッケージベンダーのためのクラウドソリューション「SQL Anywhere OnDemand Edition」ソフトウェアパッケージベンダーのためのクラウドソリューション「SQL Anywhere OnDemand Edition」
ソフトウェアパッケージベンダーのためのクラウドソリューション「SQL Anywhere OnDemand Edition」
 
ngServer and-collaboratived-development-between-san-francisco-and-tokyo
ngServer and-collaboratived-development-between-san-francisco-and-tokyongServer and-collaboratived-development-between-san-francisco-and-tokyo
ngServer and-collaboratived-development-between-san-francisco-and-tokyo
 
17 E-5 震災とHackとクラウドと 亀渕分
17 E-5 震災とHackとクラウドと 亀渕分17 E-5 震災とHackとクラウドと 亀渕分
17 E-5 震災とHackとクラウドと 亀渕分
 
アイデアを塩漬けにしない-世界中の人に手伝ってもらう方法-
アイデアを塩漬けにしない-世界中の人に手伝ってもらう方法-アイデアを塩漬けにしない-世界中の人に手伝ってもらう方法-
アイデアを塩漬けにしない-世界中の人に手伝ってもらう方法-
 
Japan Developer Summit (jp) - Cloud Foundry, the Open Platform As A Service
Japan Developer Summit (jp) - Cloud Foundry, the Open Platform As A ServiceJapan Developer Summit (jp) - Cloud Foundry, the Open Platform As A Service
Japan Developer Summit (jp) - Cloud Foundry, the Open Platform As A Service
 
ngGoBuilder and collaborative development between San Francisco and Tokyo
ngGoBuilder and collaborative development between San Francisco and TokyongGoBuilder and collaborative development between San Francisco and Tokyo
ngGoBuilder and collaborative development between San Francisco and Tokyo
 
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (後編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (後編)大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (後編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (後編)
 
【17-E-3】 オンライン機械学習で実現する大規模データ処理
【17-E-3】 オンライン機械学習で実現する大規模データ処理【17-E-3】 オンライン機械学習で実現する大規模データ処理
【17-E-3】 オンライン機械学習で実現する大規模データ処理
 
Pursuit of happiness
Pursuit of happinessPursuit of happiness
Pursuit of happiness
 
Standing female nude’’
Standing female nude’’Standing female nude’’
Standing female nude’’
 
Fuck PPT
Fuck PPTFuck PPT
Fuck PPT
 
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)
 
Ann Summers Cat 66 Slide Show
Ann Summers Cat 66 Slide ShowAnn Summers Cat 66 Slide Show
Ann Summers Cat 66 Slide Show
 
17 A QuíMica Da Pele
17 A QuíMica Da Pele17 A QuíMica Da Pele
17 A QuíMica Da Pele
 

Similaire à 削除フラグのはなし (7)

20181110 fok2018-pg-extension
20181110 fok2018-pg-extension20181110 fok2018-pg-extension
20181110 fok2018-pg-extension
 
5 古雷my sql源碼與資料庫規範
5 古雷my sql源碼與資料庫規範5 古雷my sql源碼與資料庫規範
5 古雷my sql源碼與資料庫規範
 
20190119 aws-study-pg-extension
20190119 aws-study-pg-extension20190119 aws-study-pg-extension
20190119 aws-study-pg-extension
 
MySQLとPostgreSQLの基本的な実行プラン比較
MySQLとPostgreSQLの基本的な実行プラン比較MySQLとPostgreSQLの基本的な実行プラン比較
MySQLとPostgreSQLの基本的な実行プラン比較
 
メッチャ役に立つauto_incrementの話
メッチャ役に立つauto_incrementの話メッチャ役に立つauto_incrementの話
メッチャ役に立つauto_incrementの話
 
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~
 
03 kueripahuomansuchiyuninguno shou_fa_
03 kueripahuomansuchiyuninguno shou_fa_03 kueripahuomansuchiyuninguno shou_fa_
03 kueripahuomansuchiyuninguno shou_fa_
 

Dernier

物流は成長の準備ができていますか? 警告 1 日あたり 1 章を超えて消費しないでください コンテンツが覚醒と変化への意志を引き起こす
物流は成長の準備ができていますか? 警告 1 日あたり 1 章を超えて消費しないでください コンテンツが覚醒と変化への意志を引き起こす物流は成長の準備ができていますか? 警告 1 日あたり 1 章を超えて消費しないでください コンテンツが覚醒と変化への意志を引き起こす
物流は成長の準備ができていますか? 警告 1 日あたり 1 章を超えて消費しないでください コンテンツが覚醒と変化への意志を引き起こす
Michael Rada
 

Dernier (6)

物流は成長の準備ができていますか? 警告 1 日あたり 1 章を超えて消費しないでください コンテンツが覚醒と変化への意志を引き起こす
物流は成長の準備ができていますか? 警告 1 日あたり 1 章を超えて消費しないでください コンテンツが覚醒と変化への意志を引き起こす物流は成長の準備ができていますか? 警告 1 日あたり 1 章を超えて消費しないでください コンテンツが覚醒と変化への意志を引き起こす
物流は成長の準備ができていますか? 警告 1 日あたり 1 章を超えて消費しないでください コンテンツが覚醒と変化への意志を引き起こす
 
Broadmedia Corporation. 240510fy2023_4q
Broadmedia Corporation.  240510fy2023_4qBroadmedia Corporation.  240510fy2023_4q
Broadmedia Corporation. 240510fy2023_4q
 
セルフケア研修で使えるカードゲーム『攻略!きみのストレスを発見せよ!: ゲームで身につくストレスマネジメント』
セルフケア研修で使えるカードゲーム『攻略!きみのストレスを発見せよ!: ゲームで身につくストレスマネジメント』セルフケア研修で使えるカードゲーム『攻略!きみのストレスを発見せよ!: ゲームで身につくストレスマネジメント』
セルフケア研修で使えるカードゲーム『攻略!きみのストレスを発見せよ!: ゲームで身につくストレスマネジメント』
 
company profile.pdf
company profile.pdfcompany profile.pdf
company profile.pdf
 
共有用_aio基本保守プラン_WordPressサイト_20240509.pdf
共有用_aio基本保守プラン_WordPressサイト_20240509.pdf共有用_aio基本保守プラン_WordPressサイト_20240509.pdf
共有用_aio基本保守プラン_WordPressサイト_20240509.pdf
 
事例DBサービス紹介資料(Case Study DB service introduction)
事例DBサービス紹介資料(Case Study DB service introduction)事例DBサービス紹介資料(Case Study DB service introduction)
事例DBサービス紹介資料(Case Study DB service introduction)
 

削除フラグのはなし

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6. id name pass is_deleted 1 ryu xxx FALSE 2 ken xxx FALSE 3 honda xxx TRUE
  • 7.
  • 8. id name pass is_deleted 1 ryu xxx FALSE 2 ken xxx FALSE 3 honda xxx TRUE 3 honda xxx FALSE
  • 9.
  • 10. WHERE is_deleted = false WHERE is_deleted = false WHERE is_deleted = false
  • 11. DELETE FROM users WHERE id = 2; UPDATE user SET is_update = true WHERE id = 2;
  • 12.
  • 13.
  • 14.
  • 15.
  • 16. id name pass is_deleted 1 ryu xxx TRUE 2 ryu xxx TRUE 3 ryu xxx FALSE 4 ryu xxx FALSE
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30. id name pass is_deleted 1 ryu xxx TRUE 2 ryu xxx TRUE 3 ryu xxx FALSE 4 ryu xxx FALSE
  • 31. -- 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;
  • 32.
  • 33. -- テーブルを作成する 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;
  • 34. -- 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)
  • 35. -- 更にもう一件重複する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.
  • 36. -- 削除フラグを立ててryuを削除したことにする testdb=# UPDATE users SET is_deleted = true testdb-# WHERE id = 1; UPDATE 1 -- ryuが論理削除されたことを確認 testdb=# SELECT * FROM users; id | name | pass | is_deleted ----+------+------+------------ 1 | ryu | xxx | t (1 row)
  • 37. -- 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)
  • 38. -- 削除フラグを戻して削除したryuを復活させる testdb=# UPDATE users SET is_deleted = false testdb-# WHERE id = 1; ERROR: duplicate key value violates unique constraint "users_valid_constraint" DETAIL: Key (name)=(ryu) already exists.
  • 39. -- 現在のデータを確認する 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 = true testdb-# WHERE id = 3; -- 論理削除されたryuは2件あることを確認 testdb=# SELECT * FROM users; id | name | pass | is_deleted ----+------+------+------------ 1 | ryu | xxx | t 3 | ryu | xxx | t (2 rows)
  • 40.
  • 41.
  • 42.
  • 45.
  • 46. -- ユーザテーブルを作成する -- エントリーテーブルを作成する 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 ); );
  • 47. -- 一意な部分インデックスを張る(IDを利用) CREATE UNIQUE INDEX users_valid_constraint ON users (name) WHERE 0 < user_id;
  • 48. -- テストデータを投入する 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, '参加', 'よろしく');
  • 49. -- テストデータを確認する 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)
  • 50. -- イベントを論理削除する UPDATE events SET event_id = event_id * -1 WHERE event_id = 1;
  • 51. -- 参照しているテーブルを確認する 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)
  • 52. -- ユーザを論理削除する UPDATE users SET user_id = user_id * -1 WHERE user_id = 2;
  • 53. -- 参照しているテーブルを確認する 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)
  • 54. -- ちなみに、物理削除するとON DELETE CASCADEで連鎖削除される testdb=# DELETE FROM users WHERE user_id = 1; DELETE 1 testdb=# 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)
  • 55.
  • 56.
  • 57.
  • 58.
  • 59. -- ユーザテーブルを作成する -- エントリーテーブルを作成する 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 ); );
  • 61. -- 削除されたユーザの保存先を作成する 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 );
  • 62. -- 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;
  • 63. -- DELETE時に実行するTRIGGERを仕掛ける CREATE TRIGGER trigger_users_deleted AFTER DELETE ON users FOR EACH ROW EXECUTE PROCEDURE process_deleted(); CREATE TRIGGER trigger_events_deleted AFTER DELETE ON events FOR EACH ROW EXECUTE PROCEDURE process_deleted(); CREATE TRIGGER trigger_entries_deleted AFTER DELETE ON entries FOR EACH ROW EXECUTE PROCEDURE process_deleted();
  • 64. -- テストデータを投入する 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, '参加', 'よろしく');
  • 65. -- テストデータを確認する 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)
  • 66. -- 削除されたデータの保存先は空 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)
  • 68. -- 他の関連するレコードも連鎖的に削除されている 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)
  • 69. -- 連鎖的に削除されたレコードは保存用のテーブルに退避されている 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)
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83. 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_audit AFTER INSERT OR UPDATE OR DELETE ON emp FOR EACH ROW EXECUTE PROCEDURE process_emp_audit();