SQL Server と Oracle における DELETE 文の構文差異

データベース管理において、重複レコードの削除はよくある要件である。特に、同一カード番号・金額・店舗で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;

タグ: SQL Server Oracle delete SQL構文差異 DATEDIFF

6月7日 19:45 投稿