我正在尝试创建一个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
这是因为我不能将变量用于表名吗?还有什么可能是错的,或者我将如何解决这个问题。
答案 0 :(得分:2)
这是因为我不能将变量用于表名吗?
是,或者对于列等其他模式名称。字符串变量只能在MySQL期望'
- 引用字符串的地方使用。
如果你真的需要这样做,你可以使用'动态SQL':将整个查询创建为字符串,将@tblname
连接到当时的字符串,然后使用EXECUTE执行批次。这非常难看,如果你不小心可能导致SQL注入,所以如果有任何其他选择,请避免使用它。
选择myfield FROM mytable GROUP BY
tmpcheck
HAVING(COUNT(tmpcheck
)> 1)
这对我来说似乎有问题。除非myfield
对tmpcheck
具有功能依赖性(因为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;