SQLite może używać tekstowych, rzeczywistych lub całkowitych typów danych do przechowywania dat. Co więcej, za każdym razem, gdy wykonujesz zapytanie, wyniki są wyświetlane przy użyciu formatu %Y-%m-%d %H:%M:%S
.
Teraz, jeśli wstawisz / zaktualizujesz wartości daty / godziny za pomocą funkcji daty / godziny SQLite, możesz faktycznie przechowywać milisekundy. W takim przypadku wyniki są wyświetlane przy użyciu formatu %Y-%m-%d %H:%M:%f
. Na przykład:
sqlite> create table test_table(col1 text, col2 real, col3 integer);
sqlite> insert into test_table values (
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.123'),
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.123'),
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.123')
);
sqlite> insert into test_table values (
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.126'),
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.126'),
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.126')
);
sqlite> select * from test_table;
2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
2014-03-01 13:01:01.126|2014-03-01 13:01:01.126|2014-03-01 13:01:01.126
Teraz, wykonując kilka zapytań, aby sprawdzić, czy rzeczywiście jesteśmy w stanie porównać czasy:
sqlite> select * from test_table /* using col1 */
where col1 between
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.121') and
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.125');
2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
Możesz to samo sprawdzić za SELECT
pomocą col2
i col3
uzyskasz te same wyniki. Jak widać, drugi wiersz (126 milisekund) nie jest zwracany.
Pamiętaj, że BETWEEN
zawiera, dlatego ...
sqlite> select * from test_table
where col1 between
/* Note that we are using 123 milliseconds down _here_ */
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.123') and
strftime('%Y-%m-%d %H:%M:%f', '2014-03-01 13:01:01.125');
... zwróci ten sam zestaw.
Spróbuj bawić się z różnymi zakresami dat i godzin, a wszystko będzie działać zgodnie z oczekiwaniami.
A co bez strftime
funkcji?
sqlite> select * from test_table /* using col1 */
where col1 between
'2014-03-01 13:01:01.121' and
'2014-03-01 13:01:01.125';
2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
Co powiesz na bez strftime
funkcji i bez milisekund?
sqlite> select * from test_table /* using col1 */
where col1 between
'2014-03-01 13:01:01' and
'2014-03-01 13:01:02';
2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
2014-03-01 13:01:01.126|2014-03-01 13:01:01.126|2014-03-01 13:01:01.126
Co ORDER BY
?
sqlite> select * from test_table order by 1 desc;
2014-03-01 13:01:01.126|2014-03-01 13:01:01.126|2014-03-01 13:01:01.126
2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
sqlite> select * from test_table order by 1 asc;
2014-03-01 13:01:01.123|2014-03-01 13:01:01.123|2014-03-01 13:01:01.123
2014-03-01 13:01:01.126|2014-03-01 13:01:01.126|2014-03-01 13:01:01.126
Działa dobrze.
Wreszcie, gdy mamy do czynienia z rzeczywistymi operacjami w programie (bez korzystania z pliku wykonywalnego sqlite ...)
BTW: Używam JDBC (nie jestem pewien co do innych języków) ... sterownik sqlite-jdbc v3.7.2 z Xerial - być może nowsze wersje zmieniają zachowanie wyjaśnione poniżej ... Jeśli tworzysz w Androidzie, nie robisz tego potrzebujesz sterownika jdbc. Wszystkie operacje SQL można przesyłać za pomocą SQLiteOpenHelper
.
JDBC ma różne metody, aby uzyskać rzeczywiste wartości daty / godziny z bazy danych: java.sql.Date
, java.sql.Time
, i java.sql.Timestamp
.
Związane z tym sposoby, w java.sql.ResultSet
to (oczywiście) getDate(..)
, getTime(..)
i getTimestamp()
odpowiednio.
Na przykład:
Statement stmt = ... // Get statement from connection
ResultSet rs = stmt.executeQuery("SELECT * FROM TEST_TABLE");
while (rs.next()) {
System.out.println("COL1 : "+rs.getDate("COL1"));
System.out.println("COL1 : "+rs.getTime("COL1"));
System.out.println("COL1 : "+rs.getTimestamp("COL1"));
System.out.println("COL2 : "+rs.getDate("COL2"));
System.out.println("COL2 : "+rs.getTime("COL2"));
System.out.println("COL2 : "+rs.getTimestamp("COL2"));
System.out.println("COL3 : "+rs.getDate("COL3"));
System.out.println("COL3 : "+rs.getTime("COL3"));
System.out.println("COL3 : "+rs.getTimestamp("COL3"));
}
// close rs and stmt.
Ponieważ SQLite nie ma rzeczywistego typu danych DATE / TIME / TIMESTAMP, wszystkie te 3 metody zwracają wartości, tak jakby obiekty były inicjowane za pomocą 0:
new java.sql.Date(0)
new java.sql.Time(0)
new java.sql.Timestamp(0)
Pytanie zatem brzmi: w jaki sposób możemy faktycznie wybierać, wstawiać lub aktualizować obiekty Data / Czas / Datownik?Nie ma łatwej odpowiedzi. Możesz wypróbować różne kombinacje, ale zmuszą cię do osadzenia funkcji SQLite we wszystkich instrukcjach SQL. O wiele łatwiej jest zdefiniować klasę narzędziową do przekształcania tekstu w obiekty Date w programie Java. Ale zawsze pamiętaj, że SQLite przekształca dowolną wartość daty na UTC + 0000.
Podsumowując, pomimo ogólnej zasady, aby zawsze używać poprawnego typu danych, a nawet liczb całkowitych oznaczających czas uniksowy (milisekund od epoki), znacznie łatwiej jest mi użyć domyślnego formatu SQLite ( '%Y-%m-%d %H:%M:%f'
lub w Javie 'yyyy-MM-dd HH:mm:ss.SSS'
), aby skomplikować wszystkie instrukcje SQL za pomocą Funkcje SQLite. Pierwsze podejście jest znacznie łatwiejsze do utrzymania.
DO ZROBIENIA: Sprawdzę wyniki podczas używania getDate / getTime / getTimestamp wewnątrz Androida (API15 lub nowszy) ... może wewnętrzny sterownik różni się od sqlite-jdbc ...