valeur de temps par défaut de la base de données sqlite «maintenant»

190

Est-il possible dans une base de données sqlite de créer une table qui a une colonne d'horodatage par défaut DATETIME('now')?

Comme ça:

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

Cela donne une erreur ... Comment résoudre?

Joep
la source

Réponses:

291

je crois que vous pouvez utiliser

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

à partir de la version 3.1 ( source )

Owen
la source
22
Si vous êtes préoccupé par la taille de stockage, notez que cette recette enregistrera vos horodatages au format ISO-8601 (un format texte), occupant environ 24 octets dans la base de données par date. Vous pouvez économiser de l'espace en utilisant simplement une colonne INTEGER (4) et en stockant l'heure unix via "INSERT INTO test (t) values ​​(strftime ("% s ", CURRENT_TIME));"
mckoss
3
@mckoss grâce à votre commentaire, l'instruction de création est devenue: ... mycolumn default (strftime ('% s', 'now'))
larham1
1
"... default (strftime ('% s', 'now'))" n'est pas une expression constante, ne fonctionnera pas avec la valeur par défaut en donnant "Erreur: la valeur par défaut de la colonne [...] n'est pas constante".
Mirek Rusin
@mckoss sympa, mais SQLite ignore le "(4)" après "INTEGER". Documentation SQLite: les types de données de SQLite version 3 indiquent que "les arguments numériques entre parenthèses qui suivent le nom du type.. Sont ignorés par SQLite" et que le nombre d'octets utilisés pour stocker une valeur de la classe de stockage "INTEGER" dépend "de la magnitude de la valeur ". Donc, je pense que vous avez raison de dire que SQLite le stockerait avec seulement 4 octets, mais d'ici 2038, il devrait utiliser 6 octets
ma11hew28
94

selon dr. hipp dans un article de liste récent:

CREATE TABLE whatever(
     ....
     timestamp DATE DEFAULT (datetime('now','localtime')),
     ...
);
tour
la source
Merci beaucoup! Je n'étais pas satisfait du format de CURRENT_TIMESTAMP, j'ai donc créé ma propre fonction en C pour renvoyer le nombre de microsecondes depuis l'Epoch, et je suis heureux de pouvoir l'utiliser DEFAULTmaintenant.
Michael le
39

C'est juste une erreur de syntaxe, vous avez besoin de parenthèses: (DATETIME('now'))

Si vous regardez la documentation , vous noterez la parenthèse qui est ajoutée autour de l'option 'expr' dans la syntaxe.

Adam Luter
la source
18

Ceci est un exemple complet basé sur les autres réponses et commentaires à la question. Dans l'exemple, l'horodatage ( created_at-column) est enregistré en tant que fuseau horaire UTC de l' époque Unix et converti en fuseau horaire local uniquement lorsque cela est nécessaire.

L'utilisation d'unix epoch permet d'économiser de l'espace de stockage - 4 octets entier contre 24 octets de chaîne lorsqu'il est stocké en tant que chaîne ISO8601, voir types de données . Si 4 octets ne suffisent pas, cela peut être augmenté à 6 ou 8 octets.

L'enregistrement de l'horodatage sur le fuseau horaire UTC permet d'afficher une valeur raisonnable sur plusieurs fuseaux horaires.

La version de SQLite est 3.8.6 livrée avec 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

L'heure locale est correcte car je suis situé à UTC + 2 DST au moment de la requête.

utilisateur272735
la source
7

Il peut être préférable d'utiliser le type REAL pour économiser de l'espace de stockage.

Citation de la section 1.2 des types de données dans SQLite version 3

SQLite n'a pas de classe de stockage réservée au stockage des dates et / ou des heures. Au lieu de cela, les fonctions de date et d'heure intégrées de SQLite sont capables de stocker des dates et des heures sous forme de valeurs TEXT, REAL ou INTEGER

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

voir la contrainte de colonne .

Et insérez une ligne sans fournir de valeur.

INSERT INTO "test" DEFAULT VALUES;
Nianliang
la source
1
Je préfère integer(n)où l'on peut choisir la valeur appropriée n.
user272735
4

C'est une erreur de syntaxe car vous n'avez pas écrit de parenthèses

si tu écris

Sélectionnez datetime ('now'), cela vous donnera l'heure utc, mais si vous cette requête d'écriture, vous devez ajouter des parenthèses avant cela donc (datetime ('now')) pour l'heure UTC. pour l'heure locale même Sélectionnez datetime ('now', 'localtime') pour la requête

(datetime ('maintenant', 'heure locale'))

Sandeep
la source
1

Cet exemple alternatif stocke l'heure locale en tant qu'Integer pour enregistrer les 20 octets. Le travail est effectué dans le champ par défaut, Update-trigger et View. strftime doit utiliser '% s' (guillemets simples) car "% s" (guillemets doubles) m'a renvoyé une erreur 'Not Constant'.

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
Bilbon
la source