5

我无法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

任何人都可以提供一个在不导致错误的情况下获得计数的解决方案吗?

提前致谢!

4

5 回答 5

15

这是一件很酷的事情: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;

每当你删除一行

于 2011-05-27T01:56:31.653 回答
3

使用触发器:

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将设置为最高 features_order 值加一。这迎合了被删除/更新的行,并始终保证唯一性。

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

此代码已经过测试,可以正常工作。

于 2011-05-27T01:57:28.503 回答
3
INSERT INTO `featured`
(
    `entry_id`, `featured_order`
)
VALUES
(
    200,
    (SELECT COUNT(*) AS `the_count` FROM `featured` F1)
)

更正只是添加“F1”表别名。

这个标准的 sql 解决方案适用于各种 dbms(不仅是 mysql)


我还建议对以下方面进行改进:

  • SELECT COUNT(*) +1 (问题:如果某些行被删除,您可能会与现有索引发生冲突)

  • SELECT MAX(featured_order)+1 (问题:空表的第一个插入出错)

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

于 2016-10-19T10:27:10.780 回答
2

您必须简单地使用别名来解决问题:

INSERT INTO `featured`
(
    `entry_id`, `featured_order`
)
VALUES
(
    200,
    (SELECT COUNT(*) AS `the_count` FROM `featured` as f1)
)
于 2011-05-27T05:13:01.423 回答
-1

从有关子查询的MySQL 手册中:

另一个限制是当前您不能修改表并在子查询中从同一个表中进行选择。

也许子查询中的别名或连接(否则无用)在这里会有所帮助。

编辑:事实证明有一个解决方法。解决方法在http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/进行了描述。

于 2011-05-27T01:56:38.500 回答