手动自增

6

有一个带有int字段field_1的表格。
我想插入一行新数据。
field_1的值将是所有条目最大值加上一。
我已经尝试过:

INSERT INTO table (field names, `field_1`) 
VALUES (values, '(SELECT MAX(field_1) FROM table)');  

我在field_1中得到了'0'。
我知道我可以用单独的查询来完成它。 有没有一种方法可以用一个查询执行此操作?我的意思是从php中进行一次调用。

我有一个自增字段'id',我想添加'position'字段。我希望能够更改位置,但新项目始终具有最高位置。


3
为什么您要这样做,MySQL 已经自动处理了呢? - Raj
请解释您想要实现的目标,而不是要求我们帮助您实现您认为能够实现您想要达到的目标的解决方案。 - Mike Nakis
我已经有一个自增字段了。因此,当我尝试将field_1设置为自增时,会出现以下错误:不正确的表定义;只能有一个自动列,并且必须定义为键。 - lvil
在问题中添加了一些解释 - lvil
我想把一些项目粘贴到输出列表的中间。有30行(1-30)。新行的位置将是15,因此所有其他项目都将向后移动一个位置。下一行默认为最后一行。下次我想让它成为最后一行。 - lvil
我根据你的解释扩展了我的答案。 - Mike Nakis
3个回答

8
无论您试图做什么,它都不会起作用,因为不能保证是原子性的。因此,在并行执行两个此查询的实例时,肯定会在某个随机时间点搞砸彼此,导致跳过数字和重复数字。
数据库提供自动递增的原因正是为了解决这个问题,通过保证生成这些递增值的原子性来解决问题。
(最后,“手动自动增加”是个自相矛盾的说法。它要么是“自动增加”,要么是“手动增加”。在这里只是聪明扮酷。)
编辑(根据OP的编辑):
解决您的问题的一种低效的方法是将“Position”字段保留为零或NULL,然后执行“UPDATE table SET Position = Id WHERE Position IS NULL”。 (假设您的表中的“Id”是自动编号字段。)
一种高效但繁琐的方法是在没有修改“Position”字段时将其保留为空,而只有在决定修改它时才赋予其值。然后,每次要读取“Position”字段时,使用“CASE”语句:如果“Position”字段为空,则使用“Id”的值;否则,使用“Position”的值。
编辑2(考虑OP在评论中的解释后):
如果您只有30行,我不明白为什么要在数据库中保持正确的顺序。只需将所有行加载到数组中,在任何“Position”字段被发现为空时以编程方式分配递增值,并且当行在数组中的顺序更改时,只需修复“Position”值并更新所有30行即可。

我从昨天开始就一直在思考这个问题,我编辑了我的答案并添加了一些新的见解。 - Mike Nakis

3

试试这个:

INSERT INTO table (some_random_field, field_to_increment)
SELECT 'some_random_value', IF(MAX(field_to_increment) IS NULL, 1, MAX(field_to_increment) + 1)
FROM table;

或者这样:
INSERT `table`
SET
    some_random_field = 'some_random_value',
    field_to_increment = (SELECT IF(MAX(field_to_increment) IS NULL, 1, MAX(field_to_increment) + 1) FROM table t);

顺便说一下,我知道已经晚了4年,但我正在寻找相同的答案。:)


1
ALTER TABLE table_name AUTO_INCREMENT = 1 允许数据库将 AUTO_INCREMENT 重置为 MAX(auto_increment_column)+1,而不是重置为 1。这可以防止 AUTO_INCREMENT 值的任何重复。此外,由于 AUTO_INCREMENT 值是主键/唯一的,因此永远不会发生重复。之所以提供此方法,是有原因的。它不会更改任何数据库记录,只是内部计数器,使其指向可用的最大值。正如其他人早些时候所说,不要试图超越数据库...让它处理。它很好地处理了 AUTO_INCREMENT 的重置。请参见 gotphp

答案中的链接似乎已过时。 - Pang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接