domyślna wartość czasu bazy danych sqlite „teraz”

190

Czy w bazie danych sqlite można utworzyć tabelę, która domyślnie ma kolumnę ze znacznikiem czasu DATETIME('now')?

Lubię to:

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

Daje to błąd ... Jak rozwiązać?

Joep
źródło

Odpowiedzi:

291

wierzę, że możesz użyć

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

od wersji 3.1 ( źródło )

piekarnik
źródło
22
Jeśli martwisz się wielkością pamięci, pamiętaj, że ten przepis zapisze twoje znaczniki czasu w ISO-8601 (format tekstowy), zajmując około 24 bajtów w bazie danych na dzień. Możesz zaoszczędzić miejsce, po prostu używając kolumny INTEGER (4) i przechowując czas uniksowy za pomocą „INSERT INTO test (t) wartości (strftime („% s ”, CURRENT_TIME));”
mckoss,
3
@mckoss dzięki Twojemu komentarzowi, instrukcja create stała się: ... mycolumn default (strftime ('% s', 'now'))
larham1
1
„... default (strftime ('% s', 'now'))” nie jest stałym wyrażeniem, nie będzie działać z domyślnym, dając „Błąd: domyślna wartość kolumny [...] nie jest stała”.
Mirek Rusin
@mckoss ładnie, ale SQLite ignoruje „(4)” po „INTEGER”. Dokumentacja SQLite: Typy danych W SQLite wersja 3 mówi „argumenty liczbowe w nawiasach, które następujące po nazwie typu… są ignorowane przez SQLite” i że liczba bajtów użytych do przechowywania wartości klasy pamięci „INTEGER” zależy od wielkości wartości ”. Więc myślę, że masz rację, że SQLite będzie przechowywać go z zaledwie 4 bajtami, ale do 2038 roku będzie musiał użyć 6 bajtów - mam nadzieję, że komputery będą w tym czasie kodować - i 8 bajtów do roku 4461642.
ma11hew28,
94

według dr. hipp w ostatnim poście z listy:

CREATE TABLE whatever(
     ....
     timestamp DATE DEFAULT (datetime('now','localtime')),
     ...
);
obrót silnika
źródło
Dziękuję bardzo! Nie byłem zadowolony z formatu, CURRENT_TIMESTAMPwięc utworzyłem własną funkcję w C, aby zwrócić liczbę mikrosekund od epoki, i cieszę się, że mogę tego DEFAULTteraz użyć .
Michael
39

To tylko błąd składniowy, potrzebujesz nawiasu: (DATETIME('now'))

Jeśli spojrzysz na dokumentację , zauważysz nawias dodany wokół opcji „expr” w składni.

Adam Luter
źródło
18

Jest to pełny przykład oparty na innych odpowiedziach i komentarzach do pytania. W tym przykładzie znacznik czasu ( created_at-kolumna) jest zapisywany jako strefa czasowa UTC z epoki uniksowej i konwertowany na lokalną strefę czasową tylko w razie potrzeby.

Korzystanie z epoki uniksowej oszczędza miejsce do przechowywania - 4 bajty całkowite w porównaniu z 24-bajtowym ciągiem, gdy jest przechowywany jako ciąg ISO8601, patrz typy danych . Jeśli 4 bajty to za mało, można je zwiększyć do 6 lub 8 bajtów.

Zapisywanie znacznika czasu w strefie czasowej UTC ułatwia wyświetlanie rozsądnej wartości w wielu strefach czasowych.

Wersja SQLite to 3.8.6, która jest dostarczana z 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

Czas lokalny jest poprawny, ponieważ w momencie zapytania znajduję się w UTC + 2 DST.

użytkownik272735
źródło
7

Może być lepiej użyć typu PRAWDZIWEGO, aby zaoszczędzić miejsce.

Cytat z sekcji 1.2 typów danych w SQLite wersja 3

SQLite nie ma zarezerwowanej klasy pamięci do przechowywania dat i / lub godzin. Zamiast tego wbudowane funkcje daty i godziny SQLite mogą przechowywać daty i godziny jako wartości TEXT, REAL lub INTEGER

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

patrz ograniczenie kolumny .

I wstaw wiersz bez podania żadnej wartości.

INSERT INTO "test" DEFAULT VALUES;
Nianliang
źródło
1
Wolę, integer(n)gdzie można wybrać odpowiednią wartość n.
user272735,
4

Jest to błąd składniowy, ponieważ nie napisano nawiasu

jeśli napiszesz

Wybierz datetime („teraz”), to da ci czas utc, ale jeśli napiszesz to zapytanie, musisz dodać nawias przed tym datą (datetime („teraz”)) dla czasu UTC. dla czasu lokalnego sam Wybierz datę / godzinę („teraz”, „czas lokalny”) dla zapytania

(datetime („teraz”, „czas lokalny”))

Sandeep
źródło
1

Ten alternatywny przykład przechowuje czas lokalny jako liczbę całkowitą, aby zapisać 20 bajtów. Praca jest wykonywana w polu default, Update-trigger i View. strftime musi używać „% s” (pojedyncze cudzysłowy), ponieważ „% s” (podwójne cudzysłowy) rzucił na mnie błąd „Nie stała”.

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
źródło