2021年5月29日土曜日

SQLite 3 SELECT 時の順番を指定して削除する

概要

SELECT した時の最初から何行目まで削除したい、といった場合の方法。
サブクエリを利用して順番を指定する。

実行例 (シンプルな例)

サンプルテーブル(product)
id name quantity
1 tomato 100
2 potato 120
3 pumpkin 50

上記のようなテーブルで「quantity」の値が一番小さいレコードを削除したいという場合、 以下のようなSQLとなる。 (集計関数の min()を使う方法もあるが 今回はORDER BYを使用する)

ポイントとしては

  1. サブクエリでは必ずORDER BYを指定する
  2. 出来る限り PRIMARY KEY やUNIQUEなカラムを WHERE 句で指定する
  3. WHERE 句で指定するカラムとサブクエリで取得するカラムの数と型を揃える


DELETE FROM product
WHERE
    id = (
        SELECT
            id
        FROM
            product
        ORDER BY
            quantity
        LIMIT 1
    )
;
                    
結果(product)
id name quantity
1 tomato 100
2 potato 120

実行例 (範囲を指定する)

何番目~何番目を指定する場合はサブクエリで LIMITとOFFSETを指定すればいい。 何番目だけ、としたい場合はLIMITを1にしてやればいい。

サンプルテーブル(product)
name quantity insert_date
tomato 100 2021-04-02
potato 120 2021-04-03
pumpkin 50 2021-04-02
tomato 50 2021-04-02
pumpkin 30 2021-04-01

上記のようなテーブルから「insert_date」「quantity」「name」の順番でソートした結果から 2番目〜4番目に古い(2番目から3件の)レコードを削除する場合、以下のようなSQLとなる。

ポイントとしては

  1. サブクエリでは必ずORDER BYを指定する
  2. WHERE ~ INを利用する
  3. キーになるカラムがない場合、ユニークになる条件を満たすカラムをWHEREに指定する
  4. WHEREで指定するカラムとサブクエリで取得するカラムの数と型を揃える


DELETE FROM product
WHERE (
    name
    , quantity
    , insert_date
    ) in (
        SELECT
            name
            , quantity
            , insert_date
        FROM
            product
        ORDER BY
            insert_date
            , quantity
            , name
        LIMIT 3
        OFFSET 1
    )
;
                    
結果(product)
name quantity insert_date
potato 120 2021-04-03
pumpkin 30 2021-04-01

サブクエリを使わない方法がある?

公式のドキュメントには、サブクエリを使わずに DELETE 文にそのまま ORDER BY、LIMIT、OFFSET 句をつけて実行する方法が記載されている。
ただしこれはデフォルトでは利用できず、SQLITE_ENABLE_UPDATE_DELETE_LIMITオプションを指定して ソースコードからコンパイルしなおさなければならない。
Optional LIMIT and ORDER BY clauses

参考サイト