Seitenanfang

mySQL TIMESTAMP ON UPDATE CURRENT_TIMESTAMP - Probleme

Dieser Post wurde aus meiner alten WordPress-Installation importiert. Sollte es Darstellungsprobleme, falsche Links oder fehlende Bilder geben, bitte einfach hier einen Kommentar hinterlassen. Danke.


mySQL macht selten was man erwartet, einige Sonderfälle scheinen absolut willkürlich zu sein. Dazu gehört die Verwendung von NOW() oder CURRENT_TIMESTAMP in DEFAULT-Werten einer Tabelle.

Zunächst einmal benötigen temporäre Tabellen (die ohnehin die aktuelle Verbindung nicht überdauern) zwangsweise eine Datenbank:

mysql> CREATE TEMPORARY TABLE test (`id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY(`id`));ERROR 1046 (3D000): No database selected
Das mag zwar zunächst sinnvoll erscheinen - schließlich ist eine Tabelle ohne Datenbank nicht möglich - auf den zweiten Blick stellt sich allerdings die Frage, warum diese Einschränkung auch für temporäre Tabellen gilt. Wenn mySQL eine Datenbank benötigt, kann es doch einfach eine erstellen, zumal explizit temporäre Datenbanken auch nicht unterstützt werden:
mysql> CREATE TEMPORARY DATABASE tempdb;ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DATABASE tempdb' at line 1
Nun aber zum eigentlichen Thema dieses Posts. Gegeben sei eine Tabelle mit einer TIMESTAMP-Spalte und dem Zusatz "ON UPDATE CURRENT_TIMESTAMP", alternativ auch NOW(). Das Beispiel - und so bin ich überhaupt erst auf das oben genannte Problem gestoßen - funktioniert selbstverständlich auch mit einer temporären Tabelle.
mysql> CREATE TABLE test (`id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, `updated` TIMESTAMP NOT NULL ON UPDATE NOW(), `x` INTEGER, PRIMARY KEY(`id`));Query OK, 0 rows affected (0.06 sec)

mysql> INSERT INTO test() VALUES();Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO test() VALUES();Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO test() VALUES();Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM test;+----+--------------------+------+| id | updated | x |+----+--------------------+------+| 1 | 0000-00-00 00:00:00 | NULL || 2 | 0000-00-00 00:00:00 | NULL || 3 | 0000-00-00 00:00:00 | NULL |+----+--------------------+------+3 rows in set (0.00 sec)

Die Tabelle enthält also drei Datensätze und die Spalte updated wurde - mangels expliziter DEFAULT-Angabe im CREATE TABLE - mit dem mySQL-Datumsäquivalent einer leeren Zelle initialisiert. Soweit nichts Besonderes - bis die entsprechenden Zeilen aktualisiert werden:
mysql> UPDATE test SET x=1;Query OK, 3 rows affected (0.00 sec)Rows matched: 3 Changed: 3 Warnings: 0

mysql> UPDATE test SET x=2 WHERE id=1;Query OK, 1 row affected (0.00 sec)Rows matched: 1 Changed: 1 Warnings: 0

mysql> UPDATE test SET x=1 WHERE id=2;Query OK, 0 rows affected (0.00 sec)Rows matched: 1 Changed: 0 Warnings: 0

mysql> SELECT * FROM test;+----+---------------------+---+| id | updated | x |+----+---------------------+---+| 1 | 2012-02-13 12:29:40 | 2 || 2 | 2012-02-13 12:29:30 | 1 || 3 | 2012-02-13 12:29:30 | 1 |+----+---------------------+---+3 rows in set (0.00 sec)

Der ersten UPDATE-Befehl setzt in allen Zeilen einen Wert für die Spalte x und der zweite UPDATE ändert die erste Zeile. Der letzte UPDATE-Befehl soll eigentlich die zweite Zeile ändern, übergibt allerdings den gleichen Wert für x, der sich bereits in der Tabelle befindet. MySQL bestätigt dies auch durch Rows matched: 1 Changed: 0.

MySQL versteht das ON UPDATE CURRENT TIMESTAMP nicht etwa als "aktualisiere diese Spalte bei jedem UPDATE-Befehl der diese Zeile betrifft", sondern vielmehr als "aktualisiere diese Spalte bei jedem UPDATE-Befehl, der diese Spalte tatsächlich ändert". Es reicht demnach nicht aus, eine Tabellenzeile mittels UPDATE modifizieren zu wollen, mindestens eine der Spalten dieser Zeile muss auch tatsächlich einen neuen Wert erhalten. Die Alternativ wäre ein explizites UPDATE test SET updated=NOW() WHERE id=? um den - eigentlich automatisch aktualisierten - Änderungszeitpunkt zwangsweise neu zu setzen.

 

1 Kommentar. Schreib was dazu

  1. MeMyselfAndI

    Der Grund für die Pflicht einer Datenbank ist recht simpel.
    mySQL speichert die Datenbank als Pfad lokal im Dateisystem. Alleine schon um das Überlaufen bestimmter Mointpoints zu verhindern kann es sinnvoll sein die Datenverzeichnisse z.B. per symbolischen Links aufzuteilen. Nicht jede DB muss auch zwingend im mySQL Subdir liegen.

Schreib was dazu

Die folgenden HTML-Tags sind erlaubt:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>