1

テーブルを分析して重複エントリを削除する MySQL スニペットを作成しようとしています (重複はレコード全体ではなく 2 つのフィールドに基づいています)。

クエリで変数をハードコーディングすると機能する次のコードがありますが、それらを取り出して変数として配置すると、MySQL エラーが発生します。以下はスクリプトです。

SET @tblname = 'mytable';
SET @fieldname = 'myfield';
SET @concat1 = 'checkfield1';
SET @concat2 = 'checkfield2';

ALTER TABLE @tblname ADD `tmpcheck` VARCHAR( 255 ) NOT NULL;

UPDATE @tblname SET `tmpcheck` = CONCAT(@concat1,'-',@concat2);

CREATE TEMPORARY TABLE `tmp_table` (
`tmpfield` VARCHAR( 100 ) NOT NULL
) ENGINE = MYISAM ;

INSERT INTO `tmp_table` (`tmpfield`) SELECT @fieldname FROM @tblname GROUP BY `tmpcheck` HAVING ( COUNT(`tmpcheck`) > 1 );

DELETE FROM @tblname WHERE @fieldname IN (SELECT `tmpfield` FROM `tmp_table`);

ALTER TABLE @tblname DROP `tmpcheck`;

次のエラーが表示されます。

#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@tblname ADD `tmpcheck` VARCHAR( 255 ) NOT NULL' at line 1 

これは、テーブル名に変数を使用できないためですか? 他に何が間違っている可能性があるか、またはこの問題をどのように回避しますか。

4

3 に答える 3

2

これは、テーブル名に変数を使用できないためですか?

はい、または列などの他のスキーマ名の場合。文字列変数は、MySQLが引用符で囲まれた'文字列を予期している場合にのみ使用できます。

本当にこれを行う必要がある場合は、「動的SQL」を使用できます。クエリ全体を文字列として作成し、その時点でを文字列に連結し、EXECUTE@tblnameを使用してロットを実行します。これはかなり醜く、注意しないとSQLインジェクションにつながる可能性があるため、他のオプションがある場合は避けてください。

tmpcheck(COUNT(tmpcheck)> 1)を使用してmytableGROUPからmyfieldを選択します

これは私には問題があるようです。(主キーではないため、AFAICSにはできない)myfield機能依存性がない限り、それは有効なANSISQLではありません。MySQLはそれを回避することができますが、あなたが言うことは、「値を共有する行の各グループについて、後で削除するために、そのグループからランダムに1つの行から選択する」ということです。それは本当にあなたが望むものですか?1つを除いてすべての重複を削除することをお勧めします。tmpchecktmpchecktmpcheckfieldname

通常、重複を削除するためにこの種の複雑な手順は必要ありません。DELETE-joinを使用するだけです。

DELETE my0
FROM mytable AS my0
JOIN mytable AS my1
    ON my1.checkfield1=my0.checkfield1 AND my1.checkfield2=my0.checkfield2
    AND my1.id>my0.id;

idこれは、順序付け可能なフィールドを想定しているUNIQUEため、どの行を保持するか(ここでは、最も高い行id)を決定できます。myfieldその分野かもしれませんが、文脈からはわかりません。

于 2010-05-13T12:25:54.440 に答える
1

テーブル名に変数を使用することは、実際には違法です。SQL を文字列として生成し、準備済みステートメント機能を使用して実行する必要があります。

于 2010-05-13T11:59:00.163 に答える
0

私は両方の答えを組み合わせて使用​​しました:

SET @tblname = 'myTable';
SET @idfield = 'myPrimaryKey';
SET @check1 = 'field1';
SET @check2 = 'field2';

SET @q1 = CONCAT('DELETE my0 FROM `',@tblname, '` AS my0 JOIN `',@tblname, '` AS my1 ON my1.',@check1,' = my0.',@check1,' AND my1.',@check2,' = my0.',@check2,' AND my1.',@idfield,' > my0.',@idfield,'');
PREPARE stmt1 FROM @q1;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
于 2010-05-13T13:27:08.713 に答える