Standardzeitwert der SQLite-Datenbank 'now'

190

Ist es in einer SQLite-Datenbank möglich, eine Tabelle mit einer Zeitstempelspalte zu erstellen, die standardmäßig verwendet wird DATETIME('now')?

So was:

CREATE TABLE test (
    id INTEGER PRIMARY KEY AUTOINCREMENT, 
    t TIMESTAMP DEFAULT DATETIME('now')
);

Dies gibt einen Fehler ... Wie zu beheben?

Joep
quelle

Antworten:

290

Ich glaube, Sie können verwenden

CREATE TABLE test (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  t TIMESTAMP
  DEFAULT CURRENT_TIMESTAMP
);

ab Version 3.1 ( Quelle )

Owen
quelle
22
Wenn Sie sich Gedanken über die Speichergröße machen, beachten Sie, dass dieses Rezept Ihre Zeitstempel in ISO-8601 (einem Textformat) speichert und pro Datum etwa 24 Byte in der Datenbank belegt. Sie können Platz sparen, indem Sie einfach eine INTEGER (4) -Spalte verwenden und die Unix-Zeit über "INSERT INTO test (t) -Werte (strftime ("% s ", CURRENT_TIME))" speichern.
McKoss
3
@ McKoss Dank Ihres Kommentars wurde die create-Anweisung: ... mycolumn default (strftime ('% s', 'now'))
larham1
1
"... default (strftime ('% s', 'now'))" ist kein konstanter Ausdruck, funktioniert nicht mit default und gibt "Fehler: Standardwert der Spalte [...] ist nicht konstant".
Mirek Rusin
@mckoss nett, aber SQLite ignoriert das "(4)" nach "INTEGER". SQLite-Dokumentation: Datentypen In SQLite Version 3 heißt es, dass "numerische Argumente in Klammern, die dem Typnamen folgen ... von SQLite ignoriert werden" und dass die Anzahl der Bytes, die zum Speichern eines Werts der Speicherklasse "INTEGER" verwendet werden, von der Größe abhängt des Wertes ". Ich denke, Sie haben Recht, dass SQLite es mit nur 4 Bytes speichern würde, aber bis zum Jahr 2038 müsste es 6 Bytes verwenden - hoffentlich können Computer bis dahin codieren
ma11hew28
94

nach dr. Hipp in einem aktuellen Listenbeitrag:

CREATE TABLE whatever(
     ....
     timestamp DATE DEFAULT (datetime('now','localtime')),
     ...
);
rev
quelle
Ich danke dir sehr! Ich war mit dem Format von nicht zufrieden, CURRENT_TIMESTAMPalso habe ich meine eigene Funktion in C erstellt, um die Anzahl der Mikrosekunden seit der Epoche zurückzugeben, und ich bin froh, dass ich das DEFAULTjetzt verwenden kann.
Michael
39

Es ist nur ein Syntaxfehler, Sie benötigen Klammern: (DATETIME('now'))

Wenn Sie sich die Dokumentation ansehen , werden Sie die Klammern beachten, die in der Syntax um die Option 'expr' hinzugefügt werden.

Adam Luter
quelle
18

Dies ist ein vollständiges Beispiel, das auf den anderen Antworten und Kommentaren zur Frage basiert. Im Beispiel wird der Zeitstempel ( created_at-column) als UTC-Zeitzone der Unix-Epoche gespeichert und nur bei Bedarf in die lokale Zeitzone konvertiert.

Die Verwendung der Unix-Epoche spart Speicherplatz - 4 Byte Ganzzahl vs. 24 Byte Zeichenfolge bei Speicherung als ISO8601-Zeichenfolge, siehe Datentypen . Wenn 4 Bytes nicht ausreichen, kann dies auf 6 oder 8 Bytes erhöht werden.

Durch das Speichern des Zeitstempels in der UTC-Zeitzone ist es bequem, in mehreren Zeitzonen einen angemessenen Wert anzuzeigen.

Die SQLite-Version 3.8.6 wird mit Ubuntu LTS 14.04 ausgeliefert.

$ sqlite3 so.db
SQLite version 3.8.6 2014-08-15 11:46:33
Enter ".help" for usage hints.
sqlite> .headers on

create table if not exists example (
   id integer primary key autoincrement
  ,data text not null unique
  ,created_at integer(4) not null default (strftime('%s','now'))
);

insert into example(data) values
 ('foo')
,('bar')
;

select
 id
,data
,created_at as epoch
,datetime(created_at, 'unixepoch') as utc
,datetime(created_at, 'unixepoch', 'localtime') as localtime
from example
order by id
;

id|data|epoch     |utc                |localtime
1 |foo |1412097842|2014-09-30 17:24:02|2014-09-30 20:24:02
2 |bar |1412097842|2014-09-30 17:24:02|2014-09-30 20:24:02

Die Ortszeit ist korrekt, da ich mich zum Zeitpunkt der Abfrage um UTC + 2 DST befinde.

user272735
quelle
7

Es ist möglicherweise besser, den Typ REAL zu verwenden, um Speicherplatz zu sparen.

Zitat aus Abschnitt 1.2 der Datentypen in SQLite Version 3

In SQLite ist keine Speicherklasse zum Speichern von Datum und / oder Uhrzeit reserviert. Stattdessen können die integrierten Datums- und Zeitfunktionen von SQLite Datums- und Uhrzeitangaben als TEXT-, REAL- oder INTEGER-Werte speichern

CREATE TABLE test (
    id INTEGER PRIMARY KEY AUTOINCREMENT, 
    t REAL DEFAULT (datetime('now', 'localtime'))
);

siehe Spaltenbeschränkung .

Und fügen Sie eine Zeile ohne jeden Wert bereitstellt.

INSERT INTO "test" DEFAULT VALUES;
Nianliang
quelle
1
Ich bevorzuge, integer(n)wo man den passenden Wert für wählen kann n.
user272735
4

Es handelt sich um einen Syntaxfehler, da Sie keine Klammern geschrieben haben

wenn du schreibst

Wählen Sie datetime ('now'), dann erhalten Sie utc-Zeit. Wenn Sie jedoch diese Abfrage schreiben, müssen Sie vorher eine Klammer hinzufügen (datetime ('now')) für die UTC-Zeit. für Ortszeit gleich Wählen Sie datetime ('now', 'localtime') für die Abfrage

(Datum / Uhrzeit ('jetzt', 'Ortszeit'))

Sandeep
quelle
1

In diesem alternativen Beispiel wird die Ortszeit als Ganzzahl gespeichert, um die 20 Bytes zu speichern. Die Arbeit wird in den Feldern Standard, Update-Trigger und Ansicht ausgeführt. strftime muss '% s' (einfache Anführungszeichen) verwenden, da "% s" (doppelte Anführungszeichen) einen Fehler 'Nicht konstant' auf mich geworfen hat.

Create Table Demo (
   idDemo    Integer    Not Null Primary Key AutoIncrement
  ,DemoValue Text       Not Null Unique
  ,DatTimIns Integer(4) Not Null Default (strftime('%s', DateTime('Now', 'localtime'))) -- get Now/UTC, convert to local, convert to string/Unix Time, store as Integer(4)
  ,DatTimUpd Integer(4)     Null
);

Create Trigger trgDemoUpd After Update On Demo Begin
  Update Demo Set
    DatTimUpd  =                          strftime('%s', DateTime('Now', 'localtime'))  -- same as DatTimIns
  Where idDemo = new.idDemo;
End;

Create View If Not Exists vewDemo As Select -- convert Unix-Times to DateTimes so not every single query needs to do so
   idDemo
  ,DemoValue
  ,DateTime(DatTimIns, 'unixepoch') As DatTimIns -- convert Integer(4) (treating it as Unix-Time)
  ,DateTime(DatTimUpd, 'unixepoch') As DatTimUpd --   to YYYY-MM-DD HH:MM:SS
From Demo;

Insert Into Demo (DemoValue) Values ('One');                      -- activate the field Default
-- WAIT a few seconds --    
Insert Into Demo (DemoValue) Values ('Two');                      -- same thing but with
Insert Into Demo (DemoValue) Values ('Thr');                      --   later time values

Update Demo Set DemoValue = DemoValue || ' Upd' Where idDemo = 1; -- activate the Update-trigger

Select * From    Demo;                                            -- display raw audit values
idDemo  DemoValue  DatTimIns   DatTimUpd
------  ---------  ----------  ----------
1       One Upd    1560024902  1560024944
2       Two        1560024944
3       Thr        1560024944

Select * From vewDemo;                                            -- display automatic audit values
idDemo  DemoValue  DatTimIns            DatTimUpd
------  ---------  -------------------  -------------------
1       One Upd    2019-06-08 20:15:02  2019-06-08 20:15:44
2       Two        2019-06-08 20:15:44
3       Thr        2019-06-08 20:15:44
Bilbo
quelle