2010-11-05 8 views
6

Ich habe eine INSERT Aussage, die wie folgt aussieht:ON DUPLICATE KEY UPDATE funktioniert nicht, wenn es ein Update-Trigger ist

INSERT INTO officer (officer_number, 
        name, 
        bank_id)  
VALUES ('', 
     '', 
     8) 

ON DUPLICATE KEY UPDATE officer_number = '', 
         name = '', 
         bank_id = 8, 
         id = LAST_INSERT_ID(id) 

Auf diese Weise, es zu tun einfach gut gearbeitet hat. Es funktioniert nicht, wenn ich die folgenden Trigger hinzugefügt:

CREATE TRIGGER officer_update BEFORE UPDATE ON `officer` 
FOR EACH ROW SET NEW.updated_at = NOW(), NEW.created_at = OLD.created_at 

Es ist nicht, dass der officer Datensatz wird nicht eingesetzt zu werden. Es scheint nur, dass der Auslöser Hijacking LAST_INSERT_ID() oder etwas ist. Ich sage dies, weil die nächste Abfrage, der ausgeführt wird, ist dies:

INSERT INTO account (import_id, 
        branch_id, 
        account_number, 
        officer_id, 
        customer_id, 
        open_date, 
        maturity_date, 
        interest_rate, 
        balance, 
        opening_balance) 
VALUES ('123', 
     '4567', 
     '789', 
     '0', # This is the officer id which is of course invalid 
     '321', 
     '1992-04-22', 
     '2012-05-22', 
     '0.0123', 
     '0', 
     '10000') 

Da ich Dutzende von erfolgreichen Importen mit exakt der gleichen Datei ausgeführt habe, habe ich meinen Code nicht geändert, und jetzt meine Importe nicht arbeiten Nachdem ich diesen Auslöser hinzugefügt habe, muss ich daraus schließen, dass der Auslöser der Schuldige ist. Ich hatte eine ähnliche Situation mit einem anderen Tisch und das Entfernen des Auslösers behebt das Problem.

Also meine Fragen sind:

  1. Kann jemand erklären, was, speziell ist, mein Offizier id verursacht auf 0 gesetzt werden?
  2. Was ist eine gute Lösung für dieses Problem?

Ich habe einen anderen Auslöser auf officer.created_at (und viele andere created_at s Tabellen) und ich würde es vorziehen, eine Art umständlich Lösung zu vermeiden, wo ich einen Trigger auf created_at aber eine DEFAULT CURRENT_TIMESTAMP auf updated_at haben. Aus irgendeinem Grund lässt MySQL nur einen automatischen Zeitstempel pro Tabelle zu, so dass ich CURRENT_TIMESTAMP für beide created_at und updated_at nicht tun kann.

Hier ist die SHOW CREATE TABLE für officer:

CREATE TABLE `officer` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `officer_number` varchar(255) NOT NULL, 
    `name` varchar(255) NOT NULL, 
    `bank_id` bigint(20) NOT NULL, 
    `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 
    `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `officer_number` (`officer_number`,`name`), 
    UNIQUE KEY `officer_number_2` (`officer_number`,`bank_id`), 
    KEY `bank_id` (`bank_id`), 
    CONSTRAINT `officer_ibfk_1` FOREIGN KEY (`bank_id`) REFERENCES `bank` (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=102735 DEFAULT CHARSET=latin1 
+0

Könnten Sie bitte die Ergebnisse von 'SHOW CREATE TABLE officer' und die Abfrage, die falsch funktioniert? Ihr Titel sagt 'ON DUPLICATE KEY UPDATE', aber es gibt keine solche Frage in der Post. – Quassnoi

+0

Woops. Guter Fang. Ich habe die Frage aktualisiert. –

+0

Können Sie bitte Ihren Code einfügen, den Sie verwenden, um den Wert von 'LAST_INSERT_ID()' * zurückzuziehen? scheint auf meiner Maschine gut zu funktionieren MySql 5.1.53 –

Antwort

4

Ihr INSERT ... ON DUPLICATE KEY UPDATE scheint eine Möglichkeit zu sein, einen Fehler zu verhindern, wenn officer_number bereits existiert. Benötigen Sie das Update passieren (den Trigger ausgelöst), oder könnten Sie stattdessen INSERT IGNORE verwenden:

INSERT IGNORE INTO officer (officer_number, 
        name, 
        bank_id)  
VALUES ('', 
     '', 
     8); 

, die einfach würde nichts tun, wenn officer_id bereits vorhanden ist, wodurch die Notwendigkeit für das Update zu entfernen (und damit LAST_INSERT_ID()) insgesamt.

Wenn das nicht möglich ist, dann könnte vielleicht Ihre INSERT ... ON DUPLICATE KEY UPDATE optimiert werden.Ich bin mir nicht klar über den Zweck:

id = LAST_INSERT_ID(id) 

LAST_INSERT_ID() (ohne Argumente), gibt die erste automatisch generierten Wert, der für eine AUTO_INCREMENT -Spalte von der zuletzt ausgeführten Anweisung INSERT zu beeinflussen, eine solche Spalte festgelegt wurde.

Wenn Sie jedoch ein Argument angeben, wird der Wert dieses Arguments zurückgegeben, und der nächste Aufruf von LAST_INSERT_ID() (ohne Argumente) gibt den gleichen Wert zurück. Zum Beispiel:

SELECT LAST_INSERT_ID(100); 
+---------------------+ 
| LAST_INSERT_ID(100) | 
+---------------------+ 
|     100 | 
+---------------------+ 

SELECT LAST_INSERT_ID(); 
+------------------+ 
| LAST_INSERT_ID() | 
+------------------+ 
|    100 | 
+------------------+ 

Wenn wir also davon ausgehen, dass id == 100, dann dies wahr sein sollte:

SELECT LAST_INSERT_ID(id); 
+--------------------+ 
| LAST_INSERT_ID(id) | 
+--------------------+ 
|    100 | 
+--------------------+ 

SELECT LAST_INSERT_ID(); 
+------------------+ 
| LAST_INSERT_ID() | 
+------------------+ 
|    100 | 
+------------------+ 

Im Anschluss an, dass auf:

id = LAST_INSERT_ID(id) 

gleich sein soll wie:

id = id 

Oder, wie von Josh Davis vorgeschlagen, sollte es überhaupt nicht notwendig sein. Haben Sie einfach versucht id = id? Was genau passiert, wenn Sie es ausschließen?

Die manual besagt, dass:

:

Wenn Sie jedoch Verweise auf LAST_INSERT_ID() und LAST_INSERT_ID mischen (expr), die Wirkung undefined

und ist

Die ID, die generiert wurde, ist im Server auf einem pro Verbindung Basis. Dies bedeutet, dass der Wert durch die Funktion zu einen bestimmten Client zurückgegeben wird, ist der erste AUTO_INCREMENT Wert für letzte Anweisung erzeugt eine AUTO_INCREMENT Spalte durch diesen Client zu beeinflussen. Dieser Wert kann nicht von anderen Clients beeinflusst werden, auch wenn sie AUTO_INCREMENT-Werte generieren.

, wie Sie beide LAST_INSERT_ID() und LAST_INSERT_ID(expr) verwenden, ist das Verhalten nicht definiert. Außerdem kann der TRIGGER als eine Verbindung betrachtet werden (er wird direkt auf dem Server ausgeführt), während die Anweisungen INSERT und CREATE möglicherweise von einer anderen Verbindung aufgerufen werden. Angesichts dieser und der verschiedenen Änderungen und Fehler, die mit LAST_INSERT_ID zwischen den Versionen gemeldet wurden, ist es wahrscheinlich, dass wird Probleme mit Ihrem Ansatz sein.

Zurück zu dem, was Josh Davis sagte, würde ich geneigt sein, die Verwendung von id = LAST_INSERT_ID(id) in Ihrer INSERT-Anweisung aufzulösen. Es wäre auch hilfreich zu wissen, wie Sie die officer_id in Ihrer INSERT INTO account Anweisung ableiten - die, die einen Nullwert erhält.

+0

Hier ist, was ich getan habe: Ich habe 'INSERT IGNORE' verwendet, aber wenn ich es dabei belasse, würde 'LAST_INSERT_ID()' nicht richtig angezeigt. Nach meinem 'INSERT' habe ich einfach den Datensatz ausgewählt, der mit dem übereinstimmt, was ich gerade eingefügt habe. Es ist vielleicht nicht die prägnanteste Lösung der Welt, aber es funktioniert und ich bin es leid, damit herumzuspielen. –

0

Ich verstehe nicht, warum Sie versuchen, die id zu aktualisieren. Können Sie nicht einfach den Anruf zu LAST_INSERT_ID() entfernen?

INSERT INTO officer (officer_number, 
        name, 
        bank_id) 
VALUES ('', 
     '', 
     8) 

ON DUPLICATE KEY UPDATE officer_number = '', 
         name = '', 
         bank_id = 8 

Außerdem sollten Sie Ihre MySQL-Version veröffentlichen (wie auch den Motor verwendet wird), da es einige Änderungen an LAST_INSERT_ID() Verhalten in der Vergangenheit gewesen ist.

+0

Es funktioniert nicht ohne die 'LAST_INSERT_ID()'. Ich benutze MySQL 5.1.49 und InnoDB. –

Verwandte Themen