同じ構造の2つテーブルでデータに差が在る場合、異なるデータがあるレコードを抽出する方法について。
UNIONとEXCEPTION ALLを使った方法
SQLの基本形は以下のようになります。
( SELECT * FROM [テーブル1] EXCEPT ALL SELECT * FROM [テーブル2] ) UNION ALL ( SELECT * FROM [テーブル2] EXCEPT ALL SELECT * FROM [テーブル1] )
ただし、このままだと結果が分かりづらくなるので、テーブル名表示用カラムの追加と、プライマリキーとテーブル名でソートするようなORDER BYを追加します。 テーブル名用のカラム名が衝突する場合は別の名前にしておきます。
( SELECT '[テーブル1]' AS _table_name, * FROM [テーブル1] EXCEPT ALL SELECT * FROM [テーブル2] ) UNION ALL ( SELECT '[テーブル2]' AS _table_name, * FROM [テーブル2] EXCEPT ALL SELECT * FROM [テーブル1] ) ORDER BY [プライマリーキー], _table_name
サンプル
テーブルusersとテーブルのusers_oldが以下のようになっている例を考えます。
testdb=# SELECT * FROM users ORDER BY id; id | name ----+------------ 1 | 山田たろう 2 | 佐藤花子 3 | 山下一郎 (3 行) testdb=# SELECT * FROM users_old ORDER BY id; id | name ----+---------- 1 | 山田太郎 2 | 佐藤花子 3 | 山下次郎 (3 行)
上記の2つのテーブルについて差分を取る場合、基本形のSQLでは以下のようになります。
( SELECT * FROM users EXCEPT ALL SELECT * FROM users_old ) UNION ALL ( SELECT * FROM users_old EXCEPT ALL SELECT * FROM users )
これを実行すると、結果は以下のようになります。データの順序を指定していないので、データが多いと非常に比較しづらくなります。
testdb=# ( testdb(# SELECT * FROM users testdb(# EXCEPT ALL SELECT * FROM users_old testdb(# ) UNION ALL ( testdb(# SELECT * FROM users_old testdb(# EXCEPT ALL SELECT * FROM users testdb(# ); id | name ----+------------ 3 | 山下一郎 1 | 山田たろう 3 | 山下次郎 1 | 山田太郎 (4 行)
比較しやすくするため、テーブル名表示用カラムの追加と、分かりやすくするためのソート用ORDER BYを追加します。このSQLは以下のようになります。
( SELECT 'users' AS _table_name, * FROM users EXCEPT ALL SELECT 'users' AS table_name, * FROM users_old ) UNION ALL ( SELECT 'users_old' AS _table_name, * FROM users_old EXCEPT ALL SELECT 'users_old' AS table_name, * FROM users ) ORDER BY id, _table_name実行すると以下のようになり、より見やすくなります。
testdb=# ( testdb(# SELECT 'users' AS _table_name, * FROM users testdb(# EXCEPT ALL SELECT 'users' AS table_name, * FROM users_old testdb(# ) UNION ALL ( testdb(# SELECT 'users_old' AS _table_name, * FROM users_old testdb(# EXCEPT ALL SELECT 'users_old' AS table_name, * FROM users testdb(# ) ORDER BY id, _table_name; _table_name | id | name -------------+----+------------ users | 1 | 山田たろう users_old | 1 | 山田太郎 users | 3 | 山下一郎 users_old | 3 | 山下次郎 (4 行)