valor de tiempo predeterminado de la base de datos sqlite 'ahora'

190

¿Es posible en una base de datos sqlite crear una tabla que tenga una columna de marca de tiempo predeterminada DATETIME('now')?

Me gusta esto:

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

Esto da un error ... ¿Cómo resolverlo?

Joep
fuente

Respuestas:

290

creo que puedes usar

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

a partir de la versión 3.1 ( fuente )

Owen
fuente
22
Si le preocupa el tamaño de almacenamiento, tenga en cuenta que esta receta guardará sus marcas de tiempo en ISO-8601 (un formato de texto), ocupando aproximadamente 24 bytes en la base de datos por fecha. Puede ahorrar espacio simplemente usando una columna INTEGER (4) y almacenando el tiempo unix a través de "INSERTAR en los valores de prueba (t) (strftime ("% s ", CURRENT_TIME));"
mckoss
3
@mckoss gracias a su comentario, la declaración de creación se convirtió en: ... mycolumn default (strftime ('% s', 'now'))
larham1
1
"... default (strftime ('% s', 'now'))" no es una expresión constante, no funcionará con default dando "Error: el valor predeterminado de la columna [...] no es constante".
Mirek Rusin el
@mckoss está bien, pero SQLite ignora el "(4)" después de "INTEGER". Documentación de SQLite: Tipos de datos En SQLite, la Versión 3 dice "los argumentos numéricos entre paréntesis que después del nombre del tipo ... son ignorados por SQLite" y que el número de bytes utilizados para almacenar un valor de la clase de almacenamiento "INTEGER" depende "de la magnitud del valor ". Entonces, creo que tiene razón en que SQLite lo almacenaría con solo 4 bytes, pero para el año 2038, tendría que usar 6 bytes (con suerte, las computadoras pueden codificar para entonces) y 8 bytes para el año 4461642.
ma11hew28
94

de acuerdo con el dr. hipp en una publicación reciente de la lista:

CREATE TABLE whatever(
     ....
     timestamp DATE DEFAULT (datetime('now','localtime')),
     ...
);
Rdo
fuente
Muchas gracias! No estaba satisfecho con el formato, CURRENT_TIMESTAMPasí que creé mi propia función en C para devolver la cantidad de microsegundos desde la época, y me alegro de poder usar eso DEFAULTahora.
Michael
39

Es solo un error de sintaxis, necesita paréntesis: (DATETIME('now'))

Si observa la documentación , notará el paréntesis que se agrega alrededor de la opción 'expr' en la sintaxis.

Adam Luter
fuente
18

Este es un ejemplo completo basado en las otras respuestas y comentarios a la pregunta. En el ejemplo, la marca de tiempo ( created_at-columna) se guarda como unix epoch zona horaria UTC de y se convierte a la zona horaria local solo cuando es necesario.

El uso de unix epoch ahorra espacio de almacenamiento: entero de 4 bytes frente a una cadena de 24 bytes cuando se almacena como una cadena ISO8601, consulte los tipos de datos . Si 4 bytes no es suficiente, se puede aumentar a 6 u 8 bytes.

Guardar la marca de tiempo en la zona horaria UTC hace que sea conveniente mostrar un valor razonable en varias zonas horarias.

La versión de SQLite es 3.8.6 que se incluye 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

Hora local es correcta ya que estoy ubicado en UTC + 2 DST en el momento de la consulta.

usuario272735
fuente
7

Puede ser mejor usar el tipo REAL para ahorrar espacio de almacenamiento.

Cita de la sección 1.2 de Datatypes en SQLite Versión 3

SQLite no tiene una clase de almacenamiento reservada para almacenar fechas y / u horas. En cambio, las funciones de fecha y hora integradas de SQLite son capaces de almacenar fechas y horas como valores TEXT, REAL o INTEGER

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

ver restricción de columna .

E inserte una fila sin proporcionar ningún valor.

INSERT INTO "test" DEFAULT VALUES;
Nianliang
fuente
1
Prefiero integer(n)donde uno puede elegir el valor adecuado para n.
user272735
4

Es un error de sintaxis porque no escribiste paréntesis

Si tú escribes

Seleccione datetime ('ahora'), entonces le dará tiempo utc, pero si escribe esta consulta, entonces debe agregar paréntesis antes de esto (datetime ('now')) para la hora UTC. para la hora local misma Seleccione datetime ('ahora', 'localtime') para consulta

(datetime ('ahora', 'localtime'))

Sandeep
fuente
1

Este ejemplo alternativo almacena la hora local como Integer para guardar los 20 bytes. El trabajo se realiza en el campo predeterminado, Update-trigger y View. strftime debe usar '% s' (comillas simples) porque "% s" (comillas dobles) arrojó un error 'No constante' sobre mí.

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
fuente