データベース管理において、重複レコードの削除はよくある要件である。特に、同一カード番号・金額・店舗で30秒以内に発生した取引を重複とみなすようなケースでは、DELETE 文の書き方がデータベースエンジンによって異なる。
環境情報
本例では以下の SQL Server バージョンを使用している:
Microsoft SQL Server 2012 (SP1) - 11.0.3128.0 (X64)
重複レコードの特定条件
- 同じカード番号 (
smt_salaryno) - 同じ取引金額 (
smt_transmoney) - 同じ店舗名 (
smt_org_name) - 取引時刻差が 0 秒以上 30 秒未満
- 行識別子 (
rownum_distinct) が異なる
重複レコードの検索
SQL Server および Oracle で共通して使用可能な EXISTS を使ったクエリ:
SELECT a.*
FROM dbo.ODS_CCNU_zengx_distinct a
WHERE EXISTS (
SELECT 1
FROM dbo.ODS_CCNU_zengx_distinct b
WHERE a.smt_salaryno = b.smt_salaryno
AND a.smt_transmoney = b.smt_transmoney
AND a.smt_org_name = b.smt_org_name
AND DATEDIFF(ss, a.smt_dealdatetime, b.smt_dealdatetime) >= 0
AND DATEDIFF(ss, a.smt_dealdatetime, b.smt_dealdatetime) < 30
AND a.rownum_distinct != b.rownum_distinct
)
ORDER BY a.smt_salaryno, a.smt_dealdatetime;
Oracle での削除方法
Oracle では、上記 EXISTS 句をそのまま DELETE 文に適用できる:
DELETE FROM dbo.ODS_CCNU_zengx_distinct a
WHERE EXISTS (
SELECT 1
FROM dbo.ODS_CCNU_zengx_distinct b
WHERE a.smt_salaryno = b.smt_salaryno
AND a.smt_transmoney = b.smt_transmoney
AND a.smt_org_name = b.smt_org_name
AND (b.smt_dealdatetime - a.smt_dealdatetime) * 24 * 3600 BETWEEN 1 AND 29
AND a.rownum_distinct != b.rownum_distinct
);
※ Oracle では日付差分の計算方法が異なるため、DATEDIFF の代わりに日付演算を使用する必要がある。
SQL Server での削除方法
一方、SQL Server では JOIN を使った DELETE 構文が推奨される。Oracle ではこの構文がサポートされていない点に注意が必要である:
DELETE a
FROM dbo.ODS_CCNU_zengx_distinct a
INNER JOIN dbo.ODS_CCNU_zengx_distinct b
ON a.smt_salaryno = b.smt_salaryno
AND a.smt_transmoney = b.smt_transmoney
AND a.smt_org_name = b.smt_org_name
AND DATEDIFF(ss, a.smt_dealdatetime, b.smt_dealdatetime) >= 0
AND DATEDIFF(ss, a.smt_dealdatetime, b.smt_dealdatetime) < 30
AND a.rownum_distinct != b.rownum_distinct;