valore ora predefinito del database sqlite 'ora'


190

È possibile in un database sqlite eseguire il craete di una tabella che ha una colonna timestamp di default DATETIME('now')?

Come questo:

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

Questo dà un errore ... Come risolvere?

Risposte:


291

credo che tu possa usare

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

dalla versione 3.1 ( fonte )


22
Se sei preoccupato per le dimensioni di archiviazione, nota che questa ricetta salverà i tuoi timestamp in ISO-8601 (un formato di testo), occupando circa 24 byte nel database per data. Puoi risparmiare spazio semplicemente usando una colonna INTEGER (4) e memorizzando il tempo unix tramite "INSERT INTO test (t) valori (strftime ("% s ", CURRENT_TIME));"
mckoss,

3
@mckoss grazie al tuo commento, l'istruzione create è diventata: ... mycolumn default (strftime ('% s', 'now'))
larham1

1
"... default (strftime ('% s', 'now'))" non è espressione costante, non funzionerà con l'impostazione predefinita dando "Errore: il valore predefinito della colonna [...] non è costante".
Mirek Rusin,

@mckoss nice, ma SQLite ignora "(4)" dopo "INTEGER". Documentazione SQLite: tipi di dati Nella versione 3 di SQLite dice "argomenti numerici tra parentesi che seguono il nome del tipo ... sono ignorati da SQLite" e che il numero di byte utilizzati per memorizzare un valore della classe di memoria "INTEGER" dipende "dall'entità del valore ". Quindi, penso che tu abbia ragione sul fatto che SQLite lo memorizzerebbe con solo 4 byte, ma entro l'anno 2038, avrebbe dovuto usare 6 byte - si spera, i computer possono codificare allora - e 8 byte entro l'anno 4461642.
ma11hew28

94

secondo il dott. hipp in un recente post dell'elenco:

CREATE TABLE whatever(
     ....
     timestamp DATE DEFAULT (datetime('now','localtime')),
     ...
);

Grazie mille! Non ero soddisfatto del formato di CURRENT_TIMESTAMPquindi ho creato la mia funzione in C per restituire il numero di microsecondi dall'epoca, e sono contento di poterlo usare come DEFAULTora.
Michael,

39

È solo un errore di sintassi, è necessaria la parentesi: (DATETIME('now'))

Se guardi la documentazione , noterai la parentesi che viene aggiunta intorno all'opzione 'expr' nella sintassi.


18

Questo è un esempio completo basato sulle altre risposte e commenti alla domanda. Nell'esempio il timestamp ( created_at-colonna) viene salvato come fuso orario UTC unix epoch e convertito in fuso orario locale solo quando necessario.

L'uso di unix epoch consente di risparmiare spazio di archiviazione: 4 byte interi contro 24 byte stringa se archiviati come stringa ISO8601, vedere tipi di dati . Se 4 byte non sono sufficienti, è possibile aumentarli a 6 o 8 byte.

Il salvataggio del timestamp sul fuso orario UTC rende conveniente mostrare un valore ragionevole su più fusi orari.

La versione di SQLite è la 3.8.6 fornita con Ubuntu LTS 14.04.

$ 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

Localtime è corretto in quanto mi trovo a UTC + 2 DST al momento della query.


7

Potrebbe essere meglio usare il tipo REAL, per risparmiare spazio di archiviazione.

Citazione dalla sezione 1.2 dei tipi di dati in SQLite versione 3

SQLite non ha una classe di archiviazione riservata per la memorizzazione di date e / o orari. Invece, le funzioni integrate di data e ora di SQLite sono in grado di memorizzare date e orari come valori TEXT, REAL o INTEGER

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

vedi vincolo di colonna .

E inserisci una riga senza fornire alcun valore.

INSERT INTO "test" DEFAULT VALUES;

1
Preferisco integer(n)dove si può scegliere il valore adatto per n.
user272735

4

È un errore di sintassi perché non hai scritto parentesi

se scrivi

Seleziona datetime ('now'), quindi ti darà il tempo utc ma se scrivi questa query, devi prima aggiungere la parentesi così (datetime ('now')) per UTC Time. per l'ora locale stessa Selezionare datetime ('now', 'localtime') per la query

(Datetime ( 'società', 'localtime'))


1

Questo esempio alternativo memorizza l'ora locale come numero intero per salvare i 20 byte. Il lavoro viene svolto nel campo predefinito, Aggiorna-trigger e Visualizza. strftime deve usare '% s' (virgolette singole) perché "% s" (virgolette doppie) ha generato un errore 'Non costante' su di me.

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.