2009-10-19 10 views
12

Ich habe eine einzige Tabelle mit vielen Benutzern. In dieser Tabelle habe ich die Spalte user_id (INT), die ich für jede Person getrennt erhöhen möchte. user_id MUSS bei 1Problem mit MySql INSERT MAX() + 1

beginnt Ich habe ein einfaches Beispiel hergestellt:

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

Die folgende Abfrage dies tun wird, aber es wird nur funktionieren, wenn ‚Bob‘ in der Tabelle bereits existiert ...

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

Wenn Bob nicht existiert (erster Eintrag), wird user_id auf 0 (Null) gesetzt. Das ist das Problem. Ich brauche die user_id um von 1 nicht 0 zu starten.

Antwort

16

Sie so etwas wie dieses verwenden können. Stellen Sie sicher, dass Sie sich in einer Transaktion befinden, und sperren Sie die Benutzertabelle, bevor Sie sie ausführen. Andernfalls könnten Sie zwei Bobs mit der gleichen Nummer haben.

+2

Das funktioniert! DANKE! – Chad

+2

Ja, die Abfrage funktioniert, aber bitte ignoriere den zweiten Teil nicht . :) Oder wenn Sie sich entschließen, es zu ignorieren, erstellen Sie mindestens einen eindeutigen Index für '(name, user_id)', so dass die Abfrage, die sonst ein Duplikat erzeugen würde, fehlschlägt –

+0

Tha t war meine nächste Frage tatsächlich, es ist hier: http://stackoverflow.com/questions/1590648/mysql-innodb-locking-only-the-affected-rows – Chad

1

Verwenden Sie nicht MAX() + 1 dann. Verwenden Sie ein automatisches Nummerierungsschema für die Tabelle.

Ich habe die Frage nicht richtig gelesen. Verwenden Sie Gregs Vorschlag von IFNULL().

+2

wird kein Auto-Nummerierungsschema auf der Tabellennummer jeweils nacheinander aufnehmen, anstatt den ersten „Bob“ 1 und den zweiten „Bob“ 2 machen und der erste "Tschad" 1 und dann der zweite "Tschad" 2 und so weiter? –

+1

Ich habe die Frage nicht richtig gelesen. Ich werde auf Gregs Antwort mit IFNULL() verzichten. –

6

können Sie IFNULL verwenden:

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

Aber eine solche Abfrage kann führen zu einer Race-Bedingung:

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

sieht aus wie es würde funktionieren, aber aus irgendeinem Grund löst mysql einen Syntaxfehler: ... Syntax in der Nähe von "SELECT MAX (user_id) +1 von Benutzern mit Name =" Bob "), 1)," Bob " in Zeile 1 – Chad

+0

@Chad: Ersetzen 'IFNULL (' mit 'IFNULL ((' und es funktioniert, es ist nur unsymmetrische Klammern. –

+1

Ja, deshalb hat es nicht funktioniert. Ich frage mich, welche Methode ist schneller/am besten. – Chad

3

Es war reported as a bug in MySQL.

Ich zitiere 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;