MYSQL变量 - SET @var

时间:2010-05-13 11:46:42

标签: mysql stored-procedures variables duplicate-data

我正在尝试创建一个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 

这是因为我不能将变量用于表名吗?还有什么可能是错的,或者我将如何解决这个问题。

3 个答案:

答案 0 :(得分:2)

  

这是因为我不能将变量用于表名吗?

是,或者对于列等其他模式名称。字符串变量只能在MySQL期望' - 引用字符串的地方使用。

如果你真的需要这样做,你可以使用'动态SQL':将整个查询创建为字符串,将@tblname连接到当时的字符串,然后使用EXECUTE执行批次。这非常难看,如果你不小心可能导致SQL注入,所以如果有任何其他选择,请避免使用它。

  

选择myfield FROM mytable GROUP BY tmpcheck HAVING(COUNT(tmpcheck)> 1)

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

通常,您不需要这种复杂的过程来删除重复项。只需使用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可能是那个领域,但我无法从上下文中看出来。

答案 1 :(得分:1)

对表名使用变量确实是非法的。您必须将SQL生成为字符串并使用the prepared statement feature来执行它。

答案 2 :(得分: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;