2010-05-13 89 views
1

我試圖創建一個MySQL片段,將分析表,並刪除重複項(副本是基於兩個字段而不是整個記錄)MYSQL變量 - SET @var

我有以下的代碼,我的作品時,硬編碼在查詢中的變量,但是當我帶他們出去,並把它們作爲變量,我得到的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 

這是因爲我無法使用變量作爲表名?還有什麼可能是錯的,或者我將如何解決這個問題。

回答

2

Is this because I can't use a variable for a table name?

是或其他架構名稱(如列)。字符串變量只能用於MySQL需要'引用字符串的地方。

如果您確實需要這樣做,您可以使用'動態SQL':將整個查詢創建爲一個字符串,當時將@tblname串聯到字符串中,然後使用EXECUTE執行該批次。這很醜陋,如果你不小心可能會導致SQL注入,所以如果有其他選擇,就避免使用它。

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

這對我來說似乎有問題。除非myfieldtmpcheck(它不能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可能是該領域,但我無法從上下文中看出。

1

對錶名使用變量確實是非法的。您必須以字符串形式生成SQL,並使用the prepared statement feature來執行它。

+0

現在我已經試過PREPARE stmt_name FROM; 「ALTER TABLE ADD'tmpcheck' VARCHAR(255)NOT NULL?」 SET @tblname ='mytable'; EXECUTE stmt_name USING @tblname; DEALLOCATE PREPARE stmt_name; 但在'?'處發生錯誤 – Lizard 2010-05-13 12:06:15

+0

關於不能爲表名使用變量的相同規則可能適用於語句參數。用CONCAT()連接表名,而不是將其作爲參數。 – 2010-05-13 12:08:39

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;