MySQL INSERT在同一个表上使用带有COUNT()的子查询

时间:2011-05-27 01:46:35

标签: mysql insert mysql-error-1093

我无法正常执行INSERT查询,而且我似乎无法在Google或Stack Overflow上找到解决此特定问题的任何内容。

我正在尝试为特色条目创建一个简单的表格,其中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

任何人都可以帮助获得计数而不会导致错误的解决方案吗?

提前致谢!

5 个答案:

答案 0 :(得分:14)

这是一件很酷的事:MySQL的INSERT . . . SELECT

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

不需要子查询。


@Bohemian有一个好点:

  

如果使用此方法,最好使用max(featured_order)+ 1

所以更好的查询可能是:

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:=@pos+1 FROM words;

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

DROP TABLE temp1;

每当删除一行时

答案 1 :(得分: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值加1。这适用于删除/更新的行,并始终保证唯一性。

如果表中没有行,ifnull就存在,在这种情况下,第一个值将为零。

此代码已经过测试,可以正常使用。

答案 2 :(得分:2)

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

更正只是添加“F1”表别名。 (正如上面的Angelin Nadar所建议的那样)

这应该是多数据库环境中更好的解决方案,因为相同的sintax在mysql + oracle + db2上工作正常

我还建议改进:

  • SELECT COUNT(*)+1(问题:如果某行被删除则会出错)

  • SELECT MAX(featured_order)+1(问题:第一行错误)

SELECT(COALESCE(MAX(featured_order),0)+1)(没问题)

答案 3 :(得分:1)

您必须使用能够解决问题的别名:

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

答案 4 :(得分:-1)

关于子查询的MySQL manual

  

另一个限制是,目前您无法修改表并从子查询中的同一个表中进行选择。

子查询中的别名或连接(否则无用)可能对此有所帮助。

编辑:事实证明,有一种解决方法。该变通方法被描述为http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/