How to create a table with a timestamp column that defaults to DATETIME('now')?
Like this:
CREATE TABLE test (
id INTEGER PRIMARY KEY AUTOINCREMENT,
t TIMESTAMP DEFAULT DATETIME('now')
);
This gives an error.
As of version 3.1.0 you can use CURRENT_TIMESTAMP with the DEFAULT clause:
If the default value of a column is CURRENT_TIME, CURRENT_DATE or CURRENT_TIMESTAMP, then the value used in the new row is a text representation of the current UTC date and/or time. For CURRENT_TIME, the format of the value is "HH:MM:SS". For CURRENT_DATE, "YYYY-MM-DD". The format for CURRENT_TIMESTAMP is "YYYY-MM-DD HH:MM:SS".
CREATE TABLE test (
id INTEGER PRIMARY KEY AUTOINCREMENT,
t TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
according to dr. hipp in a recent list post:
CREATE TABLE whatever(
....
timestamp DATE DEFAULT (datetime('now','localtime')),
...
);
It's just a syntax error, you need parentheses: (DATETIME('now'))
The documentation for the DEFAULT clause says:
If the default value of a column is an expression in parentheses, then the expression is evaluated once for each row inserted and the results used in the new row.
If you look at the syntax diagram you'll also notice the parentheses around 'expr'.
This is a full example based on the other answers and comments to the question. In the example the timestamp (created_at-column) is saved as unix epoch UTC timezone and converted to local timezone only when necessary.
Using unix epoch saves storage space - 4 bytes integer vs. 24 bytes string when stored as ISO8601 string, see datatypes. If 4 bytes is not enough that can be increased to 6 or 8 bytes.
Saving timestamp on UTC timezone makes it convenient to show a reasonable value on multiple timezones.
SQLite version is 3.8.6 that ships with 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 is correct as I'm located at UTC+2 DST at the moment of the query.
It may be better to use REAL type, to save storage space.
Quote from 1.2 section of Datatypes In SQLite Version 3
SQLite does not have a storage class set aside for storing dates
and/or times. Instead, the built-in Date And Time Functions of SQLite
are capable of storing dates and times as TEXT, REAL, or INTEGER
values
CREATE TABLE test (
id INTEGER PRIMARY KEY AUTOINCREMENT,
t REAL DEFAULT (datetime('now', 'localtime'))
);
see column-constraint .
And insert a row without providing any value.
INSERT INTO "test" DEFAULT VALUES;
It is syntax error because you did not write parenthesis
if you write
Select datetime('now')
then it will give you utc time but if you this write it query then you must add parenthesis before this
so (datetime('now')) for UTC Time.
for local time same
Select datetime('now','localtime')
for query
(datetime('now','localtime'))
If you want millisecond precision, try this:
CREATE TABLE my_table (
timestamp DATETIME DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
);
This will save the timestamp as text, though.
This alternative example stores the local time as Integer to save the 20 bytes. The work is done in the field default, Update-trigger, and View.
strftime must use '%s' (single-quotes) because "%s" (double-quotes) threw a 'Not Constant' error on 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
Related
I am a beginner in informix database, we want to use the irregular timeseries table to store value, but the table return wrong result after it is created, we can not found any solution, can anybody help to take a look?
our informix version is v12, platform is windows server 2012 r2.
below is our step:
---create the db space---
onspaces -c -d justtest_dbspace -p E:\IBM\Informix\12.10\INFORMIX_DWH\dbspaces\ts_testTable.000 -o 30000 -s 30000
---create the row type---
create row type rw_justtest_row (
timestamp datetime year to fraction(5),
gas_code VARCHAR(20),
avg_concentration FLOAT,
standard_name VARCHAR(50),
threshold FLOAT,
modified_date DATETIME year to second,
text1 VARCHAR(50), -- Reserved columns
text2 VARCHAR(50), -- Reserved columns
numeric1 FLOAT, -- Reserved columns
numeric2 FLOAT -- Reserved columns
);
----create the timeserie table
create table rw_justtest_table (
station_id VARCHAR(10) NOT NULL,
subdomain_id VARCHAR(20) NOT NULL,
sensor_parameter_code VARCHAR(50) NOT NULL,
period INTEGER NOT NULL,
raw_9seconds_irr TIMESERIES(rw_justtest_row)
)
lock mode row;
---create container
execute procedure TSContainerCreate('container_justtest', 'justtest_dbspace', 'rw_justtest_row', 30000, 30000);
---insert the calendar
INSERT INTO CalendarTable(c_name, c_calendar)
VALUES('ts_1sec',
'startdate(2022-06-17 00:00:00.00000),pattern({1 on}, second)');
---creatre the view table
execute procedure TSCreateVirtualTab('rw_justtest_table_v', 'rw_justtest_table',
'origin(2022-06-17 00:00:00.00000), calendar(ts_1sec), container(container_justtest), threshold(0), irregular');
---insert one reoard in side
insert into rw_justtest_table_v (station_id,subdomain_id,sensor_parameter_code, timestamp, gas_code, avg_concentration, standard_name, period, threshold) values
('YL', 'ABCDEFG','ABCDE','2022-06-17 16:00:00','ABCDE','0.222','FIGKL','60','0.09');
----check the count is 1
select count(*) from informix.rw_justtest_table_v where timestamp >= '2002-06-17 16:00:00';
---do the select to verify
select rowid,* from informix.rw_justtest_table_v where timestamp = '2022-06-17 16:00:00';
---this is the issue, below the query should not be return value, but it is still return and the timestamp is '2022-06-18 16:00:00'
select rowid,* from informix.rw_justtest_table_v where timestamp = '2022-06-18 16:00:00';
The issues is wrong result return, actually I am inserted one record only, the timestamp only '2022-06-17 16:00:00', but when I do the search for '2022-06-18 16:00:00', it is still return value and the result is wrong one. can someone expert help me?
It seems to be the behavior of the virtual table for an irregular timeseries.
From the online documentation ( Irregular time series ):
Irregular elements persist until the next element by default and
cannot be null. For example, if you query for the value of a stock
price at noon but the last recorded trade was at 11:59 AM, the query
returns the value of the price at 11:59 AM, because that value is the
nearest value equal to or earlier than noon. However, you can also
create a query to return null if the specified time stamp does not
exactly match the time stamp of an element. For example, if you query
for the price that a stock traded for at noon, but the stock did not
have a trade at noon, the query returns a null value.
I do not know how to do the query to only return when there is a value for an exact timestamp, but on the definition of the virtual table you can declare the following ( The TSVTMode parameter ):
Whether data selected by time stamp exactly matches the specified time
stamps or includes the last rows that are equal to or earlier than the
specified time stamps.
scan_discreet
1024
(0x000400) When you select data from a virtual table by time stamps,
only rows whose time stamps are exactly equal to the time stamps
specified in the query are returned.
So, when you define the virtual table, you add an extra parameter:
EXECUTE PROCEDURE TSCreateVirtualTab(
'rw_justtest_table_v',
'rw_justtest_table',
'origin(2022-06-17 00:00:00.00000), calendar(ts_1sec), container(container_justtest), threshold(0), irregular',
'scan_discreet');
Recreating the virtual table in that way, the query:
select rowid,* from informix.rw_justtest_table_v where timestamp = '2022-06-18 16:00:00';
no longer returns any rows ( using your test case ).
I am struggling to retrieve a particular row based on its exact timestamp.
CREATE TABLE PUBLIC.ERIC( SOME_ROW_ID INTEGER NOT NULL
, MY_TIMESTAMP TIMESTAMP_NTZ NOT NULL DEFAULT CAST(CURRENT_TIMESTAMP() AS TIMESTAMP_NTZ(9))
);
I insert a row in there
INSERT INTO PUBLIC.ERIC(SOME_ROW_ID) VALUES(1);
I retrieve it...
SELECT * FROM PUBLIC.ERIC;
This returns a value like this: "2020-04-07 09:58:51"
Now, if I try to retrieve that row, I keep missing it
SELECT *
FROM PUBLIC.ERIC
WHERE MY_TIMESTAMP = CAST('2020-04-07 09:58:51' AS TIMESTAMP_NTZ(9));
How am I supposed to retrieve that row?
I suppose I am getting mixed up in the timestamp thing (or precision)...
Any help greatly appreciated!
timestamp_ntz(9) has nanosecond precision, so your where clause needs to also have nanosecond precision (e.g. 2020-04-07 10:34:04.426)
I'm storing data in PostgreSQL with one column set to a default CURRENT_TIMESTAMP. I'm trying to get this default to only store: date, hours and minutes. Does anyone know how I can do it?
I need to be able to manipulate the data using Ruby to then display it on an html page. At the moment I can display a timestamp like this: 2019-09-15 12:50:05.745811 but would like something more like this: 2019-09-15 12:50.
At the moment I'm extracting each row of a table into a Ruby object and defining each value as accessible instance variable so #id = id, #content = content and #timestamp = timestamp. I would like a way to either edit a string like this: 2019-09-15 12:50:05.745811 in ruby or what I guess might be easier to find a way for the DEFAULT CURRENT_TIMESTAMP to only store the relevant data. Any help, much appreciated.
This is how my table has been created:
CREATE TABLE my_table (
id SERIAL PRIMARY KEY,
content VARCHAR(280),
timestamp timestamp DEFAULT CURRENT_TIMESTAMP
);
If you always want your date resolution only to the second then you can specify that in the definition:
CREATE TABLE my_table (
id SERIAL PRIMARY KEY,
content VARCHAR(280),
timestamp timestamp(0) DEFAULT CURRENT_TIMESTAMP
);
If you want the capability to process and/or display fractional seconds then make the conversion when selecting:
Select ..., timestamp::timestamp(0) ...
When you want to show less the second precision then you must use to_char(...) and specify the mask for what you want, So in your example 2019-09-15 12:50:
select ... to_char(timestamp, 'yyyy-mm-dd hh24:mi:'), ...
IMHO it is very bad practice to name a column the same as a data type. It will at sometime cause confusion or mistakes.
Use to_char() to remove everything after the minutes and to_timestamp() to convert back to timestamp:
CREATE TABLE my_table (
id SERIAL PRIMARY KEY,
content VARCHAR(280),
timestamp timestamp DEFAULT to_timestamp(to_char(current_timestamp, 'YYYY-MM-DD HH24:MI'), 'YYYY-MM-DD HH24:MI')
);
See the demo.
I have a SELECT that retrieves ROWS comparing a DATETIME field to the highest available value of another TABLE.
The Two Tables have the following structure
DeletedRecords
- Id (Guid)
- RecordId (Guid)
- TableName (varchar)
- DeletionDate (datetime)
And Another table which keep track of synchronizations using the following structure
SynchronizationLog
- Id (Guid)
- SynchronizationDate (datetime)
In order to get all the RECORDS that have been deleted since the last synchronization, I run the following SELECT:
SELECT
[Id],[RecordId],[TableName],[DeletionDate]
FROM
[DeletedRecords]
WHERE
[TableName] = '[dbo].[Person]'
AND [DeletionDate] >
(SELECT TOP 1 [SynchronizationDate]
FROM [dbo].[SynchronizationLog]
ORDER BY [SynchronizationDate] DESC)
The problem occurs if I do not have synchronizations available yet, the T-SQL SELECT does not return any row while it should returns all the rows cause there are no synchronization records available.
Is there a T-SQL function like COALESCE that I can use with DateTime?
Your subquery should look like something like this:
SELECT COALESCE(MAX([SynchronizationDate]), '0001-01-01')
FROM [dbo].[SynchronizationLog]
It says: Get the last date, but if there is no record (or all values are NULL), then use the '0001-01-01' date as start date.
NOTE '0001-01-01' is for DATETIME2, if you are using the old DATETIME data type, it should be '1753-01-01'.
Also please note (from https://msdn.microsoft.com/en-us/library/ms187819(v=sql.100).aspx)
Use the time, date, datetime2 and datetimeoffset data types for new work. These types align with the SQL Standard. They are more portable. time, datetime2 and datetimeoffset provide more seconds precision. datetimeoffset provides time zone support for globally deployed applications.
EDIT
An alternative solution is to use NOT EXISTS (you have to test it if its performance is better or not):
SELECT
[Id],[RecordId],[TableName],[DeletionDate]
FROM
[DeletedRecords] DR
WHERE
[TableName] = '[dbo].[Person]'
AND NOT EXISTS (
SELECT 1
FROM [dbo].[SynchronizationLog] SL
WHERE DR.[DeletionDate] <= SL.[SynchronizationDate]
)
INSERT INTO DELLL (
DATETIMEMY)
SELECT to_date(to_char(SU_MODIFYDATE, 'YYYY/MM/DD'),'YYYY/MM/DD') AS DATETIMEMY
FROM SER_TBLSERVICES WHERE SVE_SERVICEID=422
SU_MODIFYDATE = 01/18/2013
but after insertion in DELLL date (DATETIMEMY) format still same is still same
DATETIMEMY = 01/18/2013
you dont assign a format to a DATE. They are stored internally as a number and have no format. the format comes when you want to select the date. so in your case you should just do this:
first just insert the date as-is, do not try to convert it to a char and back again:
SQL> INSERT INTO DELLL (
2 DATETIMEMY) SELECT SU_MODIFYDATE
3 FROM SER_TBLSERVICES WHERE SVE_SERVICEID=422;
1 row created.
now to select it in a specific format, you can use TO_CHAR to format it.
SQL> select * from delll;
DATETIMEMY
----------
01/18/2013 <-- which isn't what you want to see, you wanted to see yyyy/mmm/dd. so...
SQL> select to_char(DATETIMEMY,'yyyy/mm/dd') DATETIMEMY from DELLL
2 /
DATETIMEMY
----------
2013/01/18
or, to apply to all selects in that session that have a date datatype, you can alter the default display format:
SQL> alter session set nls_date_format='yyyy/mm/dd';
Session altered.
SQL> select * from delll;
DATETIMEMY
----------
2013/01/18
The INSERT or SELECT in your example does not modify how a date is stored. Dates are formatted when you SELECT them, using your current connection format preferences/locale.
You are using TO_DATE, selecting that returned value is the same as with any other date, it will be formatted according to the locale.
DazzaL is right with his answer which discusses formatting, storage and retrieval of dates.
I would like to discuss what you are doing in your code.
Oracle stores dates upto precision of a seconds. In simple terms you can retrieve the date in MM/DD/YYYY HH24:MI:SS format.
By issuing to_date(to_char(SU_MODIFYDATE, 'YYYY/MM/DD'),'YYYY/MM/DD') you are actually truncating the date up to the day part. So when you try to retrieve this value, the HH24:MI:SS part will have 00:00:00 because you have truncated the date.
If you want all the details (from year, month, day to hour, minute and seconds) from SU_MODIFYDATE to be inserted into the column in DELLL, you should just use
INSERT INTO DELLL (
DATETIMEMY)
SELECT SU_MODIFYDATE AS DATETIMEMY
FROM SER_TBLSERVICES WHERE SVE_SERVICEID=422
This will ensure all parts of date in SU_MODIFYDATE column are inserted into the new column.
If you want to truncate the date, for example, upto the minute the use to_date(to_char(SU_MODIFYDATE, 'YYYY/MM/DD HH24:MI'),'YYYY/MM/DD HH24:MI')
Likewise, you can truncate dates from year part upto the second part as per your choice.
If you want to insert truncated dates then you should use the query you already have. If you want to insert dates with all their parts then avoid truncating by using to_char and to_date.