2011-05-27 69 views
5

我無法正確執行INSERT查詢,而且我似乎無法在Google或Stack Overflow上找到解決此特定問題的任何內容。MySQL INSERT在同一張表上使用帶有COUNT()的子查詢

我試圖爲精選條目創建一個簡單的表格,其中entry_id與其當前訂單一起保存到表格中。

我所需的輸出是這樣的:

如果featured表目前有以下三項:

featured_id entry_id featured_order 
1    27   0 
2    54   1 
4    23   2 

我想下一個條目保存與featured_order = 3。

我試圖讓下面的查詢,沒有運氣的工作:

INSERT INTO `featured` 
(
    `entry_id`, `featured_order` 
) 
VALUES 
(
    200, 
    (SELECT COUNT(*) AS `the_count` FROM `featured`) 
) 

我得到的錯誤是:You can't specify target table 'featured' for update in FROM clause

任何人都可以幫助一個解決方案,獲得計數而不會導致錯誤?

在此先感謝!

+0

可能重複http://stackoverflow.com/questions/45494/sql-delete-不能重複的 - 這個問題是刪除;不能重複指定目標表中的更新從條款 – Tim 2011-05-27 01:52:06

+2

不是重複的 - 這個問題是刪除;這是爲了插入。這裏根本不適用。 – Bohemian 2011-05-27 03:09:45

回答

13

這是一個很酷的事情:MySQL的INSERT . . . SELECT

INSERT INTO `featured` 
(
    `entry_id`, `featured_order` 
) 
SELECT 200, COUNT(*) + 1 
FROM `featured` 

無需子查詢。


@Bohemian好點:

Better to use max(featured_order) + 1 if you use this approach

因此,一個更好的查詢可能會是:

INSERT INTO `featured` 
(
    `entry_id`, `featured_order` 
) 
SELECT 200, MAX(`featured_order`) + 1 
FROM `featured` 

他的觸發方式,在他的回答形容也是完成一個好辦法你想要什麼。


與查詢1中的潛在問題是,如果你刪除行的排名將被揭去,你會在featured_order有重複。對於第二個查詢,這不是問題,但是您將有空位,就像您使用自動增量列一樣。

如果你絕對必須有沒有間隙的訂單最好的解決辦法,我知道的是運行這一系列的查詢:

SET @pos:=0; 

DROP TABLE IF EXISTS temp1; 

CREATE TEMPORARY TABLE temp1 LIKE featured; 

ALTER TABLE featured ORDER BY featured_order ASC; 

INSERT INTO temp1 (featured_id, entry_id, featured_order) 
SELECT featured_id, entry_id, @pos:[email protected]+1 FROM words; 

UPDATE featured 
JOIN temp1 ON featured.featured_id = temp1.featured_id 
SET featured.rank = temp1.rank; 

DROP TABLE temp1; 

當你刪除行

+0

我不認爲這會奏效。從['INSERT ... SELECT'](http://dev.mysql.com/doc/refman/5.5/en/insert-select.html)的文檔:「但是,您不能插入到表中並選擇來自子查詢中的同一張表。「 – 2011-05-27 01:59:11

+1

問題與此:a)您將要添加一個計數(*),b)如果編號不與count(*)對齊 - 例如,如果行被刪除。如果使用這種方法,最好使用max(featured_order)+ 1 – Bohemian 2011-05-27 01:59:40

+0

@Ted - 在本地數據庫上測試它 - 在那裏工作得很好。 – jisaacstone 2011-05-27 02:01:52

-1

MySQL manual關於子查詢:

Another restriction is that currently you cannot modify a table and select from the same table in a subquery.

也許一個別名或連接(否則無用)在子查詢中會有所幫助。

編輯:事實證明,有一種解決方法。解決方法描述爲http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/

+0

「解決問題」涉及到後續的「更新」陳述 - 幾乎沒有「優雅」。 – Bohemian 2011-05-27 02:07:57

+0

我希望我不暗示「優雅」:) – 2011-05-27 02:16:53

2

使用觸發器:

drop trigger if exists featured_insert_trigger; 

delimiter // 
create trigger featured_insert_trigger before insert on featured 
for each row 
begin 
    set new.featured_order = ifnull((select max(featured_order) from featured), -1) + 1; 
end; // 
delimiter ; 

現在你的刀片是這樣的:

insert into featured (entry_id) values (200); 

featured_order將被設置爲最高值featured_order加一。這適用於刪除/更新的行,並始終保證唯一性。

ifnull在表中沒有行的情況下,在這種情況下,第一個值將爲零。

此代碼已經過正確測試。

+0

我對觸發器做了一些研究(我以前從未聽說過),這絕對聽起來像是最好的解決方案。 然而,當我嘗試了,我得到這個錯誤: 'TRIGGER命令拒絕用戶「XXXX」 @「XXXX」表「featured'' 我已經給MySQL用戶‘所有特權’,根據HostGator,所以它看起來像一個觸發器不在這個項目的卡片中。 :/ – jlengstorf 2011-05-27 18:23:37

+0

這是否工作,如果有兩個插入完全在同一時間? – xms 2017-08-11 08:04:51

+0

@xms從來沒有任何更新/插入發生在「完全相同的時間」。數據庫串行化所有變異查詢。每一個都始終以原子方式開始和完成。 – Bohemian 2017-08-11 10:36:49

1

你必須simpley,將解決這個問題使用別名:

INSERT INTO `featured` 
(
    `entry_id`, `featured_order` 
) 
VALUES 
(
    200, 
    (SELECT COUNT(*) AS `the_count` FROM `featured` as f1) 
) 
+0

如果對eith -vote提供的解釋會更好,這將有所幫助 – 2011-05-27 06:45:55

+0

錯誤拼寫還是錯誤答案? – 2011-05-27 07:29:50

2
INSERT INTO `featured` 
(
    `entry_id`, `featured_order` 
) 
VALUES 
(
    200, 
    (SELECT COUNT(*) AS `the_count` FROM `featured` F1) 
) 

修正只是將 「F1」 表的別名。 (正如Angelin納達爾的正上方建議)

這應該是一個多分貝的環境中更好的解決方案,因爲同一sintax工作在MySQL + ORACLE + DB2精細


我也建議過的改進:

  • SELECT COUNT(*)+1(問題:如果行被刪除你的錯誤)

  • SELECT MAX(featured_order)+1(問題:第一個行誤差)

SELECT(COALESCE(MAX(featured_order),0)+1)(沒有問題)

+0

我只是想知道...如果有兩個插入在同一時間,這工作會好嗎? – xms 2017-08-11 08:05:46