1

我正在尝试创建一个 MySQL 片段,它将分析表并删除重复条目(重复项基于两个字段而不是整个记录)

当我对查询中的变量进行硬编码时,我有以下代码可以工作,但是当我将它们取出并将它们作为变量放置时,我得到 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 需要'-quoted 字符串的地方使用。

如果您真的需要这样做,您可以使用“动态 SQL”:将整个查询创建为字符串,然后将其连接到字符串中,然后使用EXECUTE@tblname执行该批次。这很丑陋,如果您不小心,可能会导致 SQL 注入,因此如果有任何其他选择,请避免使用它。

SELECT myfield FROM mytable GROUP BY tmpcheckHAVING ( COUNT( tmpcheck) > 1 )

这对我来说似乎有问题。除非myfield有功能依赖tmpcheck(它不能依赖哪个 AFAICS,因为tmpcheck它不是主键),否则这不是有效的 ANSI SQL。MySQL 会让你侥幸逃脱,但你要说的是“对于共享值为 的每组行,从该组中随机tmpcheck选择fieldname一行以供以后删除”。这真的是你想要的吗?我希望您想要删除除一个重复项之外的所有重复项。

通常,您不需要这种复杂的过程来删除重复项。只需使用 DELETE 连接:

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 回答