2009-10-19 53 views
12

我有一个包含许多用户的表。在那张表中,我有一个名为user_id(INT)的列,我想为每个人单独增加。 USER_ID必须从1开始问题与MySql INSERT MAX()+ 1

我已经准备了一个简单的例子:

Showing all names 
+--------------+-----------------------+ 
| user_id  | name     | 
+--------------+-----------------------+ 
| 1   | Bob     | 
| 1   | Marry     | 
| 2   | Bob     | 
| 1   | John     | 
| 3   | Bob     | 
| 2   | Marry     | 
+--------------+-----------------------+ 


Showing only where name = Bob 
+--------------+-----------------------+ 
| user_id  | name     | 
+--------------+-----------------------+ 
| 1   | Bob     | 
| 2   | Bob     | 
| 3   | Bob     | 
+--------------+-----------------------+ 

下面的查询将做到这一点,但如果“鲍勃”表中已经存在,它只会工作...

INSERT INTO users(user_id, name) SELECT(SELECT MAX(user_id)+1 from users where 
name='Bob'), 'Bob'; 

如果Bob不存在(第一项)user_id设置为0(零)。这就是问题。我需要user_id从1开始而不是0.

回答

16

您可以使用这样的事情:

INSERT INTO users (user_id, name) 
SELECT 1 + coalesce((SELECT max(user_id) FROM users WHERE name='Bob'), 0), 'Bob'; 

但是这样的查询可能导致竞争条件。确保您处于事务中,并在运行之前锁定用户表。否则,最终可能会有两个相同编号的Bob。

+2

This Works!THANK YOU! – Chad 2009-10-19 08:58:53

+2

是的,查询工作,但请不要忽略第二部分。:)或者如果你决定忽略它,至少在'(name,user_id)'上创建一个唯一索引,这样否则会产生重复的查询将失败。 – 2009-10-19 11:54:46

+0

t实际上是我的下一个问题,它在这里:http://stackoverflow.com/questions/1590648/mysql-innodb-locking-only-the-affected-rows – Chad 2009-10-19 19:41:22

1

请勿使用MAX()+ 1。在桌上使用自动编号方案。

我没有正确地阅读这个问题。使用Greg的建议IFNULL()。

+2

不会对表号自动编号方案的每个记录顺序,而不是使第一“鲍勃” 1,第二个“鲍勃” 2,和第一个“乍得”1,然后第二个“乍得”2等? – 2009-10-19 08:43:28

+1

我没有正确阅读这个问题。我会按照IFNULL()的格式回答Greg的问题。 – 2009-10-19 08:48:14

6

您可以使用IFNULL

INSERT INTO users(user_id, name) 
SELECT(IFNULL((SELECT MAX(user_id)+1 from users where name='Bob'), 1), 'Bob'; 
+1

看起来像它会工作,但由于某种原因,mysql会抛出一个语法错误: ...在用户附近使用'SELECT MAX(user_id)+1'时使用的语法,其中name ='Bob'),1),'Bob''在第1行 – Chad 2009-10-19 08:57:20

+0

@Chad:用'IFNULL替换'IFNULL((''并且它可以工作,它只是不平衡的括号) – 2009-10-19 09:02:14

+1

是的,这就是为什么它不起作用,我不知道哪种方法更快/最好。 – Chad 2009-10-19 09:08:52

3

这是reported as a bug in MySQL

我引述吉扬Bichot:

Second, here is the simplest of workarounds:
instead of using:
insert into foo(lfd) values((select max(lfd) from foo)+1)
just do
insert into foo(lfd) select (max(lfd)+1) from foo;