5

MySQL テーブルに保存されているレコードをクリーンアップしようとしています。行に が含まれている場合、%X%内容に関係なく、その行とそのすぐ下の行を削除する必要があります。例 (テーブルが誰かの知性を侮辱している場合は申し訳ありません):

| 1 | leave alone 
| 2 | Contains %X% - Delete
| 3 | This row should also be deleted
| 4 | leave alone
| 5 | Contains %X% - Delete
| 6 | This row should also be deleted
| 7 | leave alone

いくつかのクエリのみを使用してこれを行う方法はありますか? または、最初に (検索パラメーターを使用して) SELECT クエリを実行し、%x%次にそれらの結果をループして、返されたインデックスごとに + 1 の DELETE...WHERE を実行する必要がありますか?

4

4 に答える 4

2

少し不格好ですが、これは機能するはずです (パターン マッチングを使用するため、LIKE 引数を確認する必要があるかもしれません (コメントを参照) DELETE FROM table. db WHERE idcolIN ( SELECT idcolFROM db. tableWHERE colLIKE '%X%') OR idcol IN ( SELECTidcol +1 FROMdb .table WHEREcol` LIKE '%バツ%')

于 2013-03-17T04:40:14.243 に答える
1

テーブルに名前が付けられ、 および という名前の列testに含まれているとします。iddata

前の行を持つすべての行の id (現在の行の id よりも小さいすべての id の最大の id) を提供する SELECT から始めます。

SELECT t1.id FROM test t1
  JOIN test t2 ON
    ( t2.id, true )
      =
    ( SELECT t3.id, t3.data LIKE '%X%' FROM test t3
        WHERE t3.id < t1.id ORDER BY id DESC LIMIT 1 )

これにより、ID 3 と 6 が得られます。その前の行 2 と 5 には が含まれ%X%ているので、これで問題ありません。

%X%次に、UNION を使用して、それらを含む行の ID を取得し、前の行と結合します。

(SELECT t1.id FROM test t1
  JOIN test t2 ON
    ( t2.id, true )
      =
    ( SELECT t3.id, t3.data LIKE '%X%' FROM test t3
        WHERE t3.id < t1.id ORDER BY id DESC LIMIT 1 )
)
UNION
(
  SELECT id FROM test WHERE data LIKE '%X%'
)

これにより、3、6、2、5 が得られます。

ここで、テーブルから削除して MySQL の同じテーブルから選択することはできません。一時テーブルを使用して、削除する ID をそこに保存し、その一時テーブルから読み取って元のテーブルから削除します。 :

CREATE TEMPORARY TABLE deleteids (id INT);

INSERT INTO deleteids
  (SELECT t1.id FROM test t1
    JOIN test t2 ON
      ( t2.id, true )
        =
      ( SELECT t3.id, t3.data LIKE '%X%' FROM test t3
          WHERE t3.id < t1.id ORDER BY id DESC LIMIT 1 )
  )
  UNION
  (
    SELECT id FROM test WHERE data LIKE '%X%'
  );

  DELETE FROM test WHERE id in (SELECT * FROM deleteids);

...そして、テーブルには ID 1、4、および 7 が残っていtestます!

(また、前の行は <、ORDER BY、および LIMIT を使用して選択されるため、ID が連続していない場合にも機能します。)

于 2013-03-17T05:47:26.563 に答える
1

DELETEすべてを 1 つのステートメントで実行できます。

「直後の行」が INT ベースの ID 列の順序に基づいていると仮定すると、MySQL 変数を使用して、ID のギャップを考慮した行番号を割り当てることができます。

DELETE a FROM tbl a
JOIN (
    SELECT a.id, b.id AS nextid
    FROM (
        SELECT     a.id, a.text, @rn:=@rn+1 AS rownum 
        FROM       tbl a
        CROSS JOIN (SELECT @rn:=1) rn_init
        ORDER BY   a.id
    ) a
    LEFT JOIN (
        SELECT     a.id, @rn2:=@rn2+1 AS rownum 
        FROM       tbl a
        CROSS JOIN (SELECT @rn2:=0) rn_init
        ORDER BY   a.id
    ) b ON a.rownum = b.rownum
    WHERE a.text LIKE '%X%'
) b ON a.id IN (b.id, b.nextid)

SQL Fiddle Demo (たとえば、追加データを追加)


これが何をするかというと、最初にデータを取得し、ID 列に基づいてランク付けします。次にLEFT JOIN、ランク列が だけ遅れていることを除いて、ほぼ同じ結果セットに対してオフセットを行います1DELETEこれにより、行とその直後の「次の」行が並べて取得されるため、親ステートメントで両方の ID を同時に取得できます。

SELECT a.id, a.text, b.id AS nextid, b.text AS nexttext
FROM (
    SELECT     a.id, a.text, @rn:=@rn+1 AS rownum 
    FROM       tbl a
    CROSS JOIN (SELECT @rn:=1) rn_init
    ORDER BY   a.id
) a
LEFT JOIN (
    SELECT     a.id, a.text, @rn2:=@rn2+1 AS rownum 
    FROM       tbl a
    CROSS JOIN (SELECT @rn2:=0) rn_init
    ORDER BY   a.id
) b ON a.rownum = b.rownum
WHERE a.text LIKE '%X%'

収量:

ID     | TEXT                   | NEXTID   | NEXTTEXT
2      | Contains %X% - Delete  | 3        | This row should also be deleted
5      | Contains %X% - Delete  | 6        | This row should also be deleted
257    | Contains %X% - Delete  | 3434     | This row should also be deleted
4000   | Contains %X% - Delete  | 4005     | Contains %X% - Delete
4005   | Contains %X% - Delete  | 6000     | Contains %X% - Delete
6000   | Contains %X% - Delete  | 6534     | This row should also be deleted

次に、 JOINIDDELETEが「サブ選択」IDまたはNEXTID.

于 2013-03-17T05:47:38.583 に答える
0

単一のクエリでこれを行う合理的な方法はありません。(可能かもしれませんが、最終的に使用しなければならないクエリは不当に複雑になり、ほぼ確実に他の SQL エンジンに移植できなくなります。)

質問で説明したSELECT-then-DELETEアプローチを使用してください。

于 2013-03-17T04:37:15.353 に答える