2009-10-19 16 views
12

Ho una singola tabella contenente molti utenti. In quella tabella ho una colonna chiamata user_id (INT), che voglio incrementare separatamente per ogni persona. id_utente deve iniziare a 1Problema con MySql INSERT MAX() + 1

ho preparato un semplice esempio:

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     | 
+--------------+-----------------------+ 

La query seguente farà questo, ma funzionerà solo se 'Bob' esiste già nella tabella ...

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

Se Bob non esiste (prima immissione) user_id è impostato su 0 (zero). Questo è il problema. Ho bisogno di user_id per iniziare da 1 non 0.

risposta

16

si può usare qualcosa di simile:

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

Ma tale richiesta può portare ad una condizione di competizione. Assicurati di essere in una transazione e blocchi la tabella degli utenti prima di eseguirla. Altrimenti potresti finire con due Bob con lo stesso numero.

+2

Questo funziona! GRAZIE! – Chad

+2

Sì, la query funziona, ma per favore non ignorare la seconda parte . :) O se si decide di ignorarlo, almeno creare un indice univoco su '(nome, user_id)' in modo che la query che altrimenti produrrebbe un duplicato fallisce –

+0

era la mia prossima domanda in realtà, è qui: http://stackoverflow.com/questions/1590648/mysql-innodb-locking-only-the-affected-rows – Chad

1

Non utilizzare MAX() + 1 quindi. Utilizza uno schema di numerazione automatica sul tavolo.

Non ho letto correttamente la domanda. Usa il suggerimento di Greg di IFNULL().

+2

volontà non uno schema di numerazione automatica sul numero della tabella ogni record in sequenza, piuttosto che fare il primo "Bob" 1 e il secondo "Bob" 2, e il primo "Chad" 1 e poi il secondo "Chad" 2 e così via? –

+1

Non ho letto correttamente la domanda. Mi rimanderò alla risposta di Greg con IFNULL(). –

6

È possibile utilizzare IFNULL:

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

sembra funzionare, ma per qualche motivo mysql genera un errore di sintassi: ... sintassi da utilizzare vicino a "SELECT MAX (user_id) +1 dagli utenti dove name =" Bob "), 1)," Bob " alla riga 1 – Chad

+0

@Chad: Sostituisci 'IFNULL (' con 'IFNULL ((' e funzionerà, è solo parentesi sbilanciate. –

+1

Sì, è per questo che non ha funzionato.Mi domando quale metodo sia più veloce/migliore – Chad

3

È stato reported as a bug in MySQL.

che sto citando Guilhem 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;