2008-09-05 83 views
444

我在我的數據庫中有一個表story_category,包含損壞的條目。接下來的查詢將返回損壞的項目:MySQL錯誤1093 - 無法在FROM子句中指定更新的目標表

SELECT * 
FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN 
     story_category ON category_id=category.id); 

我試圖刪除它們執行:

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category 
     INNER JOIN story_category ON category_id=category.id); 

,但我得到了一個錯誤:

#1093 - You can't specify target table 'story_category' for update in FROM clause

我如何克服這個問題?

+2

相關:http://stackoverflow.com/a/14302701/238419 – 2013-02-22 18:10:06

+0

好像MySQL錯誤跟蹤器中的功能請求位於:[無法更新表並從子查詢中的同一個表中選擇](https://bugs.mys ql.com/bug.php?id=23353) – 2017-12-30 06:32:26

回答

578

更新:這個答案涵蓋了一般的錯誤分類。有關如何最好地處理業務方案的確切查詢更具體的答案,請參閱其他回答這個問題

在MySQL中,你不能修改您在SELECT部分​​使用相同的表。
這種行爲記錄在: http://dev.mysql.com/doc/refman/5.6/en/update.html

也許你可以加入表本身

如果邏輯就足以重新塑造查詢,失去了子查詢,並加入表簡單本身,採用適當的選擇標準。這將導致MySQL將該表視爲兩個不同的事物,從而允許破壞性更改繼續。

UPDATE tbl AS a 
INNER JOIN tbl AS b ON .... 
SET a.col = b.col 

或者,嘗試嵌套子查詢深入FROM子句...

如果您絕對需要子查詢,有一個變通方法,但它是 醜陋的人,有幾個原因,包括性能:

UPDATE tbl SET col = (
    SELECT ... FROM (SELECT.... FROM) AS x); 

在FROM子句創建一個隱式臨時 表嵌套子查詢,所以它不會被視爲您正在更新的同一張表。

......但要注意查詢優化器

然而,提防從MySQL 5.7.6及以後,優化器可以優化出來的子查詢,仍然給你的錯誤。幸運的是,optimizer_switch變量可用於關閉此行爲;儘管我不能推薦這樣做,不僅僅是短期修復,還是小型的一次性任務。

SET optimizer_switch = 'derived_merge=off'; 

感謝Peter V. Mørch這個建議的意見。

示例技術來自Baron Schwartz,originally published at Nabble,在這裏作了釋義和擴展。

+1

Upvoted這個答案,因爲我不得不刪除項目,並不能從另一個表中獲取信息,必須從同一個表中查詢。由於這是彈出的頂部,而谷歌搜索錯誤,我得到了這將是最適合我的答案,很多人試圖從同一個表subquerieing更新。 – HMR 2012-12-12 03:36:56

+2

@Cheekysoft,爲什麼不把值保存到變量中呢? – Pacerier 2015-02-24 03:47:27

+15

請注意,從[MySQL 5.7.6 on](http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-6.html)中,優化器可以優化子 - 查詢並仍然給你的錯誤,除非你`SET optimizer_switch ='derived_merge = off';`:-( – 2015-11-06 15:36:41

4

您可以將所需行的ID插入臨時表中,然後刪除該表中找到的所有行。

這可能是@Cheekysoft在兩個步驟中所做的。

1

如果有什麼不工作,直通前門到來時,再取後門:

drop table if exists apples; 
create table if not exists apples(variety char(10) primary key, price int); 

insert into apples values('fuji', 5), ('gala', 6); 

drop table if exists apples_new; 
create table if not exists apples_new like apples; 
insert into apples_new select * from apples; 

update apples_new 
    set price = (select price from apples where variety = 'gala') 
    where variety = 'fuji'; 
rename table apples to apples_orig; 
rename table apples_new to apples; 
drop table apples_orig; 

它速度快。數據越大越好。

+7

而且你剛剛失去了所有外鍵,也許你還有一些級聯刪除 – Walf 2014-12-09 06:48:49

98

您的子查詢中的inner join是不必要的。看起來您希望刪除story_category中的條目,其中category_id不在category表中。相反

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category); 

的是:

做這個

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT DISTINCT category.id 
    FROM category INNER JOIN 
     story_category ON category_id=category.id); 
11

這是我做了更新優先級列值由1如果是> = 1的表格,並在其WHERE子句在同一個表上使用子查詢以確保至少有一行包含Priority = 1(因爲這是執行更新時要檢查的條件):


UPDATE My_Table 
SET Priority=Priority + 1 
WHERE Priority >= 1 
AND (SELECT TRUE FROM (SELECT * FROM My_Table WHERE Priority=1 LIMIT 1) as t); 

我知道這有點醜,但它確實很好。

28
DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT cid FROM (
     SELECT DISTINCT category.id AS cid FROM category INNER JOIN story_category ON category_id=category.id 
    ) AS c 
) 
192

NexusRex與來自同一個表連接刪除提供very good solution

如果你這樣做:

DELETE FROM story_category 
WHERE category_id NOT IN (
     SELECT DISTINCT category.id AS cid FROM category 
     INNER JOIN story_category ON category_id=category.id 
) 

你會得到一個錯誤。

但是,如果你在一個包裹條件更選擇

DELETE FROM story_category 
WHERE category_id NOT IN (
    SELECT cid FROM (
     SELECT DISTINCT category.id AS cid FROM category 
     INNER JOIN story_category ON category_id=category.id 
    ) AS c 
) 

它會做正確的事!

說明:查詢優化器對所述第一查詢一個derived merge optimization(從而導致它失敗,錯誤),但第二個查詢不符合的衍生合併優化因此優化器被強制爲首先執行子查詢。

77

,近來我在同一個表,我沒有像下面更新記錄:

UPDATE skills AS s, (SELECT id FROM skills WHERE type = 'Programming') AS p 
SET s.type = 'Development' 
WHERE s.id = p.id; 
3

根據 the Mysql UPDATE Syntax由@CheekySoft相連,它的權利在底部說。

Currently, you cannot update a table and select from the same table in a subquery.

我想你是從store_category中刪除,同時仍然從工會中選擇它。

1

嘗試將Select語句的結果保存在單獨的變量中,然後將其用於刪除查詢。

10

如果你不能做到

UPDATE table SET a=value WHERE x IN 
    (SELECT x FROM table WHERE condition); 

,因爲它是在同一個表,你可以欺騙和做:

UPDATE table SET a=value WHERE x IN 
    (SELECT * FROM (SELECT x FROM table WHERE condition) as t) 

[更新或刪除或任何]

0

怎麼樣此查詢希望它有幫助

DELETE FROM story_category LEFT JOIN (SELECT category.id FROM category) cat ON story_category.id = cat.id WHERE cat.id IS NULL 
0

當您在子查詢中引用父查詢表時,最簡單的方法是使用表別名。

例子:

insert into xxx_tab (trans_id) values ((select max(trans_id)+1 from xxx_tab)); 

將其更改爲:

insert into xxx_tab (trans_id) values ((select max(P.trans_id)+1 from xxx_tab P)); 
0

試試這個

DELETE FROM story_category 
WHERE category_id NOT IN (
SELECT DISTINCT category.id 
FROM (SELECT * FROM STORY_CATEGORY) sc; 
相關問題