SlideShare a Scribd company logo
1 of 83
Download to read offline
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();

More Related Content

What's hot

オンプレを少しずつコンテナ化する
オンプレを少しずつコンテナ化するオンプレを少しずつコンテナ化する
オンプレを少しずつコンテナ化するKenkichi Okazaki
 
わかった気になるMySQL
わかった気になるMySQLわかった気になるMySQL
わかった気になるMySQLyoku0825
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」Takuto Wada
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Scott Wlaschin
 
OpenTelemetryでWebシステムの処理を追跡しよう - DjangoCongress JP 2022
OpenTelemetryでWebシステムの処理を追跡しよう - DjangoCongress JP 2022OpenTelemetryでWebシステムの処理を追跡しよう - DjangoCongress JP 2022
OpenTelemetryでWebシステムの処理を追跡しよう - DjangoCongress JP 2022Takayuki Shimizukawa
 
テストコードの DRY と DAMP
テストコードの DRY と DAMPテストコードの DRY と DAMP
テストコードの DRY と DAMPYusuke Kagata
 
Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugMasatoshi Tada
 
純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門Kimikazu Kato
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ増田 亨
 
3週連続DDDその2 深いモデルの探求(ドメイン駆動設計 第3部)
3週連続DDDその2  深いモデルの探求(ドメイン駆動設計 第3部)3週連続DDDその2  深いモデルの探求(ドメイン駆動設計 第3部)
3週連続DDDその2 深いモデルの探求(ドメイン駆動設計 第3部)増田 亨
 
Spring Data JPAによるデータアクセス徹底入門 #jsug
Spring Data JPAによるデータアクセス徹底入門 #jsugSpring Data JPAによるデータアクセス徹底入門 #jsug
Spring Data JPAによるデータアクセス徹底入門 #jsugMasatoshi Tada
 
テストコード入門
テストコード入門テストコード入門
テストコード入門小川 昌吾
 
ソーシャルゲーム案件におけるDB分割のPHP実装
ソーシャルゲーム案件におけるDB分割のPHP実装ソーシャルゲーム案件におけるDB分割のPHP実装
ソーシャルゲーム案件におけるDB分割のPHP実装infinite_loop
 
分解のススメ 第14回 ローエンド中BT Audio SoC華BT Audio SoCLowEndChineseBTAudioSoC.pdf
分解のススメ 第14回 ローエンド中BT Audio SoC華BT Audio SoCLowEndChineseBTAudioSoC.pdf分解のススメ 第14回 ローエンド中BT Audio SoC華BT Audio SoCLowEndChineseBTAudioSoC.pdf
分解のススメ 第14回 ローエンド中BT Audio SoC華BT Audio SoCLowEndChineseBTAudioSoC.pdfMasawo Yamazaki
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)Takuto Wada
 
MySQLおじさんの逆襲
MySQLおじさんの逆襲MySQLおじさんの逆襲
MySQLおじさんの逆襲yoku0825
 
ドメイン駆動で開発する ラフスケッチから実装まで
ドメイン駆動で開発する ラフスケッチから実装までドメイン駆動で開発する ラフスケッチから実装まで
ドメイン駆動で開発する ラフスケッチから実装まで増田 亨
 
ウェブセキュリティの常識
ウェブセキュリティの常識ウェブセキュリティの常識
ウェブセキュリティの常識Hiroshi Tokumaru
 
分散システムの限界について知ろう
分散システムの限界について知ろう分散システムの限界について知ろう
分散システムの限界について知ろうShingo Omura
 

What's hot (20)

オンプレを少しずつコンテナ化する
オンプレを少しずつコンテナ化するオンプレを少しずつコンテナ化する
オンプレを少しずつコンテナ化する
 
わかった気になるMySQL
わかった気になるMySQLわかった気になるMySQL
わかった気になるMySQL
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014Domain Driven Design with the F# type System -- F#unctional Londoners 2014
Domain Driven Design with the F# type System -- F#unctional Londoners 2014
 
OpenTelemetryでWebシステムの処理を追跡しよう - DjangoCongress JP 2022
OpenTelemetryでWebシステムの処理を追跡しよう - DjangoCongress JP 2022OpenTelemetryでWebシステムの処理を追跡しよう - DjangoCongress JP 2022
OpenTelemetryでWebシステムの処理を追跡しよう - DjangoCongress JP 2022
 
テストコードの DRY と DAMP
テストコードの DRY と DAMPテストコードの DRY と DAMP
テストコードの DRY と DAMP
 
Java ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsugJava ORマッパー選定のポイント #jsug
Java ORマッパー選定のポイント #jsug
 
純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
 
3週連続DDDその2 深いモデルの探求(ドメイン駆動設計 第3部)
3週連続DDDその2  深いモデルの探求(ドメイン駆動設計 第3部)3週連続DDDその2  深いモデルの探求(ドメイン駆動設計 第3部)
3週連続DDDその2 深いモデルの探求(ドメイン駆動設計 第3部)
 
Spring Data JPAによるデータアクセス徹底入門 #jsug
Spring Data JPAによるデータアクセス徹底入門 #jsugSpring Data JPAによるデータアクセス徹底入門 #jsug
Spring Data JPAによるデータアクセス徹底入門 #jsug
 
テストコード入門
テストコード入門テストコード入門
テストコード入門
 
ソーシャルゲーム案件におけるDB分割のPHP実装
ソーシャルゲーム案件におけるDB分割のPHP実装ソーシャルゲーム案件におけるDB分割のPHP実装
ソーシャルゲーム案件におけるDB分割のPHP実装
 
分解のススメ 第14回 ローエンド中BT Audio SoC華BT Audio SoCLowEndChineseBTAudioSoC.pdf
分解のススメ 第14回 ローエンド中BT Audio SoC華BT Audio SoCLowEndChineseBTAudioSoC.pdf分解のススメ 第14回 ローエンド中BT Audio SoC華BT Audio SoCLowEndChineseBTAudioSoC.pdf
分解のススメ 第14回 ローエンド中BT Audio SoC華BT Audio SoCLowEndChineseBTAudioSoC.pdf
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
 
MySQLおじさんの逆襲
MySQLおじさんの逆襲MySQLおじさんの逆襲
MySQLおじさんの逆襲
 
Are Design Patterns Dead?
Are Design Patterns Dead?Are Design Patterns Dead?
Are Design Patterns Dead?
 
ドメイン駆動で開発する ラフスケッチから実装まで
ドメイン駆動で開発する ラフスケッチから実装までドメイン駆動で開発する ラフスケッチから実装まで
ドメイン駆動で開発する ラフスケッチから実装まで
 
ウェブセキュリティの常識
ウェブセキュリティの常識ウェブセキュリティの常識
ウェブセキュリティの常識
 
分散システムの限界について知ろう
分散システムの限界について知ろう分散システムの限界について知ろう
分散システムの限界について知ろう
 

Viewers also liked

Layout analyzerでのgroovyの利用について
Layout analyzerでのgroovyの利用についてLayout analyzerでのgroovyの利用について
Layout analyzerでのgroovyの利用についてkimukou_26 Kimukou
 
Building scalablewebapps
Building scalablewebappsBuilding scalablewebapps
Building scalablewebappsAyumu Aizawa
 
ソフトウェアパッケージベンダーのためのクラウドソリューション「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-tokyoSatoshi Tanaka
 
17 E-5 震災とHackとクラウドと 亀渕分
17 E-5 震災とHackとクラウドと 亀渕分17 E-5 震災とHackとクラウドと 亀渕分
17 E-5 震災とHackとクラウドと 亀渕分Keiji Kamebuchi
 
アイデアを塩漬けにしない-世界中の人に手伝ってもらう方法-
アイデアを塩漬けにしない-世界中の人に手伝ってもらう方法-アイデアを塩漬けにしない-世界中の人に手伝ってもらう方法-
アイデアを塩漬けにしない-世界中の人に手伝ってもらう方法-nishio
 
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 ServicePatrick Chanezon
 
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 Tokyonotolab
 
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (後編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (後編)大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (後編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (後編)Yuuki Namikawa
 
【17-E-3】 オンライン機械学習で実現する大規模データ処理
【17-E-3】 オンライン機械学習で実現する大規模データ処理【17-E-3】 オンライン機械学習で実現する大規模データ処理
【17-E-3】 オンライン機械学習で実現する大規模データ処理Developers Summit
 
Pursuit of happiness
Pursuit of happinessPursuit of happiness
Pursuit of happinessbioideology
 
Standing female nude’’
Standing female nude’’Standing female nude’’
Standing female nude’’may
 
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)
大規模化するピグライフを支えるインフラ ~MongoDBとChefについて~ (前編)Akihiro Kuwano
 
Ann Summers Cat 66 Slide Show
Ann Summers Cat 66 Slide ShowAnn Summers Cat 66 Slide Show
Ann Summers Cat 66 Slide ShowMargaret_R
 
17 A QuíMica Da Pele
17 A QuíMica Da Pele17 A QuíMica Da Pele
17 A QuíMica Da PeleClaudia Lage
 

Viewers also liked (16)

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
 

Similar to 削除フラグのはなし

20181110 fok2018-pg-extension
20181110 fok2018-pg-extension20181110 fok2018-pg-extension
20181110 fok2018-pg-extensionToshi Harada
 
5 古雷my sql源碼與資料庫規範
5 古雷my sql源碼與資料庫規範5 古雷my sql源碼與資料庫規範
5 古雷my sql源碼與資料庫規範Ivan Tu
 
20190119 aws-study-pg-extension
20190119 aws-study-pg-extension20190119 aws-study-pg-extension
20190119 aws-study-pg-extensionToshi Harada
 
MySQLとPostgreSQLの基本的な実行プラン比較
MySQLとPostgreSQLの基本的な実行プラン比較MySQLとPostgreSQLの基本的な実行プラン比較
MySQLとPostgreSQLの基本的な実行プラン比較Shinya Sugiyama
 
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~Nobuhisa Koizumi
 
03 kueripahuomansuchiyuninguno shou_fa_
03 kueripahuomansuchiyuninguno shou_fa_03 kueripahuomansuchiyuninguno shou_fa_
03 kueripahuomansuchiyuninguno shou_fa_Kaito Tonooka
 

Similar to 削除フラグのはなし (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_
 

Recently uploaded

JAPAN WEB3.0 AWARD 2023 ブロックチェーン(NFT)技術を活用したアイディア 優秀賞作品 遺3.0相続
JAPAN WEB3.0 AWARD 2023 ブロックチェーン(NFT)技術を活用したアイディア 優秀賞作品 遺3.0相続JAPAN WEB3.0 AWARD 2023 ブロックチェーン(NFT)技術を活用したアイディア 優秀賞作品 遺3.0相続
JAPAN WEB3.0 AWARD 2023 ブロックチェーン(NFT)技術を活用したアイディア 優秀賞作品 遺3.0相続Yusuke Katsuma
 
株式会社MAVEL会社概要_アフィリエイト広告_運用型広告_LTVを予測しLOIを最適化する広告代理店
株式会社MAVEL会社概要_アフィリエイト広告_運用型広告_LTVを予測しLOIを最適化する広告代理店株式会社MAVEL会社概要_アフィリエイト広告_運用型広告_LTVを予測しLOIを最適化する広告代理店
株式会社MAVEL会社概要_アフィリエイト広告_運用型広告_LTVを予測しLOIを最適化する広告代理店ssuserfb441f
 
chouhou_obuse_reiwa6nenn_4_2404slide.pdf
chouhou_obuse_reiwa6nenn_4_2404slide.pdfchouhou_obuse_reiwa6nenn_4_2404slide.pdf
chouhou_obuse_reiwa6nenn_4_2404slide.pdfssuser31dbd1
 
答えのないコンセンサスゲーム「無人島での出来事」運営用パワーポイントスライド説明資料
答えのないコンセンサスゲーム「無人島での出来事」運営用パワーポイントスライド説明資料答えのないコンセンサスゲーム「無人島での出来事」運営用パワーポイントスライド説明資料
答えのないコンセンサスゲーム「無人島での出来事」運営用パワーポイントスライド説明資料Jun Chiba
 
HCCソフト株式会社 2025年新卒採用向け 会社紹介・採用情報資料------
HCCソフト株式会社 2025年新卒採用向け 会社紹介・採用情報資料------HCCソフト株式会社 2025年新卒採用向け 会社紹介・採用情報資料------
HCCソフト株式会社 2025年新卒採用向け 会社紹介・採用情報資料------ssusercbaf23
 
第15回販促コンペ 審査員個人賞(林 知幸 氏) アルカナ? アディダスジャパン
第15回販促コンペ 審査員個人賞(林 知幸 氏) アルカナ? アディダスジャパン第15回販促コンペ 審査員個人賞(林 知幸 氏) アルカナ? アディダスジャパン
第15回販促コンペ 審査員個人賞(林 知幸 氏) アルカナ? アディダスジャパンYusuke Katsuma
 
20240424 zaim academy counseling lesson .pdf
20240424 zaim academy counseling lesson .pdf20240424 zaim academy counseling lesson .pdf
20240424 zaim academy counseling lesson .pdfssuser80a51f
 
コダワリ抜いた経営指南書(概要版) - コダワリ・ビジネス・コンサルティング株式会社
コダワリ抜いた経営指南書(概要版) - コダワリ・ビジネス・コンサルティング株式会社コダワリ抜いた経営指南書(概要版) - コダワリ・ビジネス・コンサルティング株式会社
コダワリ抜いた経営指南書(概要版) - コダワリ・ビジネス・コンサルティング株式会社hmoriyama
 

Recently uploaded (10)

JAPAN WEB3.0 AWARD 2023 ブロックチェーン(NFT)技術を活用したアイディア 優秀賞作品 遺3.0相続
JAPAN WEB3.0 AWARD 2023 ブロックチェーン(NFT)技術を活用したアイディア 優秀賞作品 遺3.0相続JAPAN WEB3.0 AWARD 2023 ブロックチェーン(NFT)技術を活用したアイディア 優秀賞作品 遺3.0相続
JAPAN WEB3.0 AWARD 2023 ブロックチェーン(NFT)技術を活用したアイディア 優秀賞作品 遺3.0相続
 
KestrelPro Flyer Japan IT Week 2024 (Japanese)
KestrelPro Flyer Japan IT Week 2024 (Japanese)KestrelPro Flyer Japan IT Week 2024 (Japanese)
KestrelPro Flyer Japan IT Week 2024 (Japanese)
 
株式会社MAVEL会社概要_アフィリエイト広告_運用型広告_LTVを予測しLOIを最適化する広告代理店
株式会社MAVEL会社概要_アフィリエイト広告_運用型広告_LTVを予測しLOIを最適化する広告代理店株式会社MAVEL会社概要_アフィリエイト広告_運用型広告_LTVを予測しLOIを最適化する広告代理店
株式会社MAVEL会社概要_アフィリエイト広告_運用型広告_LTVを予測しLOIを最適化する広告代理店
 
chouhou_obuse_reiwa6nenn_4_2404slide.pdf
chouhou_obuse_reiwa6nenn_4_2404slide.pdfchouhou_obuse_reiwa6nenn_4_2404slide.pdf
chouhou_obuse_reiwa6nenn_4_2404slide.pdf
 
company profile
company profilecompany profile
company profile
 
答えのないコンセンサスゲーム「無人島での出来事」運営用パワーポイントスライド説明資料
答えのないコンセンサスゲーム「無人島での出来事」運営用パワーポイントスライド説明資料答えのないコンセンサスゲーム「無人島での出来事」運営用パワーポイントスライド説明資料
答えのないコンセンサスゲーム「無人島での出来事」運営用パワーポイントスライド説明資料
 
HCCソフト株式会社 2025年新卒採用向け 会社紹介・採用情報資料------
HCCソフト株式会社 2025年新卒採用向け 会社紹介・採用情報資料------HCCソフト株式会社 2025年新卒採用向け 会社紹介・採用情報資料------
HCCソフト株式会社 2025年新卒採用向け 会社紹介・採用情報資料------
 
第15回販促コンペ 審査員個人賞(林 知幸 氏) アルカナ? アディダスジャパン
第15回販促コンペ 審査員個人賞(林 知幸 氏) アルカナ? アディダスジャパン第15回販促コンペ 審査員個人賞(林 知幸 氏) アルカナ? アディダスジャパン
第15回販促コンペ 審査員個人賞(林 知幸 氏) アルカナ? アディダスジャパン
 
20240424 zaim academy counseling lesson .pdf
20240424 zaim academy counseling lesson .pdf20240424 zaim academy counseling lesson .pdf
20240424 zaim academy counseling lesson .pdf
 
コダワリ抜いた経営指南書(概要版) - コダワリ・ビジネス・コンサルティング株式会社
コダワリ抜いた経営指南書(概要版) - コダワリ・ビジネス・コンサルティング株式会社コダワリ抜いた経営指南書(概要版) - コダワリ・ビジネス・コンサルティング株式会社
コダワリ抜いた経営指南書(概要版) - コダワリ・ビジネス・コンサルティング株式会社
 

削除フラグのはなし

  • 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();