H2 database string to timestamp - h2

Insertion of timestamps in H2 database
Hello, I have to insert data like '17-09-2012 18:47:52.69'. Function PARSEDATETIME cuts milliseconds.
Query example:
CREATE TABLE TEST(ID NUMBER(19) not null,
DATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
INSERT INTO TEST (ID, DATE) VALUES(1,
parsedatetime('17-09-2012 18:47:52.69', 'dd-MM-yyyy hh:mm:ss.SS'))
After SELECT I see that milliseconds are zeroes.
What is solution?

According to my test, with H2 version 1.3.170, the milliseconds are not actually zero, but 069:
select * from test;
ID DATE
1 2012-09-17 18:47:52.069
The same happens if you run:
call parsedatetime('17-09-2012 18:47:52.69', 'dd-MM-yyyy hh:mm:ss.SS');
If you add a zero then it works:
call parsedatetime('17-09-2012 18:47:52.690', 'dd-MM-yyyy hh:mm:ss.SS');
H2 internally uses java.text.SimpleDateFormat, so it has to live with the same limitations. If you find a solution within SimpleDateFormat, you can use it within the parsedatetime function in H2.
An alternative is to use the ISO timestamp format as defined in JDBC. This is supposed to work with all databases that conform the JDBC standard:
INSERT INTO TEST VALUES(2, {ts '2012-09-17 18:47:52.69'});

Related

Why is DATE data type treated like TIMESTAMP(0) data type in Oracle mode in H2?

According to the H2 documentation, in the Oracle compatibility mode:
DATE data type is treated like TIMESTAMP(0) data type.
Meantime, DATE and TIMESTAMP(0) datatypes are not the same in Oracle. Compare:
SELECT CAST(SYSDATE AS TIMESTAMP(0)), CAST(SYSDATE AS DATE) from dual
gives
25-MAR-22 13.07.42.000000000 25-MAR-22
respectively.
In particular, this weird treating of DATE as TIMESTAMP(0) influences on how H2 calculates the difference between two dates.
Again, in Oracle:
SELECT CAST(TO_DATE('2022-01-05', 'YYYY-MM-DD') AS TIMESTAMP(0)) - CAST(TO_DATE('2022-01-01', 'YYYY-MM-DD') AS TIMESTAMP(0)) from dual
gives
+04 00:00:00.000000
and
SELECT CAST(TO_DATE('2022-01-05', 'YYYY-MM-DD') AS DATE) - CAST(TO_DATE('2022-01-01', 'YYYY-MM-DD') AS DATE) from dual
produces just:
4
Apparently, for H2 both above queries produce the result in nanoseconds and not days as expected.
So, it is an H2 bug or I am missing something?
Meantime, DATE and TIMESTAMP(0) datatypes are not the same in Oracle
Oracle differs from many other RDBMS in that its DATE data type ALWAYS contains both a date and a time component. Its implementation predates the ANSI standard.
In Oracle, if you have the table:
CREATE TABLE table_name (ts TIMESTAMP(0), dt DATE);
and insert the data:
INSERT INTO table_name (ts, dt) VALUES (SYSDATE, SYSDATE);
Then you can look at the binary data being stored using the DUMP function:
SELECT DUMP(ts) AS dump_ts,
DUMP(dt) AS dump_dt
FROM table_name;
Which outputs:
DUMP_TS
DUMP_DT
Typ=180 Len=7: 120,122,3,25,15,13,37
Typ=12 Len=7: 120,122,3,25,15,13,37
Then you can see that they are both stored as 7-byte binary values:
120 = Century + 100
122 = Year-of-century + 100
3 = Month
25 = Day
15 = Hour + 1
13 = Minutes + 1
37 = Seconds + 1
And the binary values are identical (the only difference is in the meta-data Typ where 180 = TIMESTAMP and 12 = DATE).
Effectively, they are stored identically.
db<>fiddle here
However
The side-effects of a TIMESTAMP vs. a DATE data type in Oracle may lead to different effects.
When you subtract a TIMESTAMP and either a TIMESTAMP or a DATE then the return value is an INTERVAL DAY TO SECOND data type.
When you subtract a DATE and a DATE then the default return value is a NUMBER representing the number of days difference.
When you display a TIMESTAMP then the client application you are using may default to using the NLS_TIMESTAMP_FORMAT session parameter to format the timestamp as a string and the default for this parameter will typically show date, time and fractional seconds.
When you display a DATE then the client application you are using may default to using the NLS_DATE_FORMAT session parameter to format the date as a string and the default for this parameter will show date but not time (and there will never be any fractional seconds to show). Just because the client application may chose not to show the time component does not mean that the time component does not exist.
If you set the session parameters using:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
Then, provided your client application is using those parameters to format them, they will display identically.
The problem you are seeing with the difference in Oracle is due to these side effects.
If the question is
So, it is an H2 bug or I am missing something?
than the the answer would be:
No, it is not a bug, and what you've missed is the fact, that compatibility modes in H2 are just that - attempt to reach with minimal efforts maximum compatibility with different databases.
H2 is not an emulator for any non-standard features (quirks) of those databases.
It that particular case, to achieve identical behaviour would require to introduce new non-standard data type, which goes beyond "minimal effort" level.
The different in the output of the values in the first query is down to the session's NLS settings. These control the display format for dates and timestamps:
sho parameter nls_date_format
NAME TYPE VALUE
--------------- ------ -----------
nls_date_format string DD-MON-YYYY
sho parameter nls_timestamp_format
NAME TYPE VALUE
-------------------- ------ -------------------------
nls_timestamp_format string DD-MON-YYYY HH24.MI.SSXFF
SELECT CAST(SYSDATE AS TIMESTAMP(0)), CAST(SYSDATE AS DATE) from dual;
CAST(SYSDATEASTIMESTAMP(0)) CAST(SYSDAT
------------------------------ -----------
25-MAR-2022 12.18.24.000000000 25-MAR-2022
If you change these to be the same format, both expressions return the same result:
alter session set nls_date_format = 'DD-MON-YYYY HH24:MI:SS';
alter session set nls_timestamp_format = 'DD-MON-YYYY HH24:MI:SS';
SELECT CAST(SYSDATE AS TIMESTAMP(0)), CAST(SYSDATE AS DATE) from dual;
CAST(SYSDATEASTIMEST CAST(SYSDATEASDATE)
-------------------- --------------------
25-MAR-2022 12:17:43 25-MAR-2022 12:17:43
So they both contain the full date + time with no fractional seconds.
Note that while date and timestamp(0) have the same precision, as your further examples show they work differently:
Subtracting one date from another returns the number of days between the values as a number
Subtracting a timestamp from a date or timestamp returns an interval
So the result of:
SELECT CAST(TO_DATE('2022-01-05', 'YYYY-MM-DD') AS DATE) - CAST(TO_DATE('2022-01-01', 'YYYY-MM-DD') AS DATE) from dual
Is 4 days.

Oracle SQL Developer- How to force 00:00:00 hour when inserting a new DATE value

In my Oracle SQL Developer, i have a table with a column with DATE format. When i insert a new row into this table, and insert a new value in this column, it automatically suggestes me the current date with the current hour.
I would like that it automatically suggestes me current date, but with 00:00:00 hour . Is there some setting or parameter that i can set in my SQL Developer to have this result?
We can't able to insert 00:00:00 hours ... the hour value should be between 1 to 12...
we can use below query to insert 00:00:00 hours but the value will be changed to 12:00:00
INSERT INTO TABLE (DATE_COL) VALUES
( TO_DATE ('11/16/2017 00:00:00 ', 'MM/DD/YYYY HH24:MI:SS '));
It seems to me that your DATE column is set with a DEFAULT of SYSDATE. This means, for any INSERT operations which do not specify a value in your DATE column, the current date and time will populate for that row. However, if INSERT operations do specify a value in your DATE column, then the specified date value will supersede the DEFAULT of SYSDATE.
If an application is controlling INSERT operations on that table, then one solution is to ensure the application utilizes the TRUNC() function to obtain your desired results. For example:
INSERT INTO tbl_target
(
col_date,
col_value
)
VALUES
(
TRUNC(SYSDATE, 'DDD'),
5000
)
;
However, if there are multiple applications or interfaces where users could be inserting new rows into the table, (e.g. using Microsoft Access or users running INSERT statements via SQL Developer) and you can't force all of those interfaces to utilize the TRUNC() function on that column during insertion, then you need to look into other options.
If you can ensure via applications that INSERT operations will not actually reference the DATE, then you can simply ALTER the table so that the DATE column will have a DEFAULT of TRUNC(SYSDATE). A CHECK CONSTRAINT can be added for further integrity:
ALTER TABLE tbl_target
MODIFY
(
col_date DATE DEFAULT TRUNC(SYSDATE, 'DDD') NOT NULL
)
ADD
(
CONSTRAINT tbl_target_CHK_dt CHECK(col_date = TRUNC(col_date, 'DDD'))
)
;
However, if users still have the freedom to specify the DATE when inserting new rows, you will want to use a TRIGGER:
CREATE OR REPLACE TRIGGER tbl_target_biu_row
BEFORE INSERT OR UPDATE OF col_val
ON tbl_target
FOR EACH ROW
BEGIN
:NEW.col_date := TRUNC(SYSDATE, 'DDD');
END tbl_target_biu_row
;
This will take of needing to manage the application code of all external INSERT operations on the table. Keep in mind, the above trigger is also modifying the DATE column if a user updates the specified value column.

Why doesn't this Oracle DATE comparison work

In Oracle 12, if I create a very simple table, TEST_TABLE, with a single varchar2(128) column 'name' and populate that column with lots of strings of '20170831', and my sysdate shows:
SELECT sysdate FROM dual;
29-SEP-17
then why does this SQL query return 0 rows:
SELECT TO_DATE(name,'YYYYMMDD'),
TO_DATE(TRUNC(SYSDATE),'DD-MM-YYYY')
FROM TEST_TABLE
WHERE TO_DATE(name,'YYYYMMDD') < TO_DATE(TRUNC(SYSDATE),'DD-MM-YYYY');
(This is a very simplified example of a problem I'm facing in my partition maintenance script and have not been able to solve for the last week).
Thank you in advance for any assistance related to the above query.
Midnight(time part is 00:00:00.000):
SELECT TO_DATE(name,'YYYYMMDD'), TRUNC(SYSDATE)
FROM TEST_TABLE
WHERE TO_DATE(name,'YYYYMMDD') <= TRUNC(SYSDATE);
You could also try:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
Just don't apply a to_date() to an already date field, this because, it will implicitly convert that date into varchar and then apply the to_date() function to it, for example your query part TO_DATE(TRUNC(SYSDATE),'DD-MM-YYYY') is interpreted like this:
TO_DATE(TO_CHAR(TRUNC(SYSDATE)),'DD-MM-YYYY')
TO_CHAR(TRUNC(SYSDATE)) is getting a char something like: '31-AUG-17', and that is not in 'DD-MM-YYYY' format.
And because of that, TO_DATE(TRUNC(SYSDATE),'DD-MM-YYYY') gets something like this: 29/09/0017 and your filter goes FALSE and gets no results.

How to insert date in Oracle 10g xe?

I did the following:
CREATE TABLE BOOK(
BOOK_ID VARCHAR(4) PRIMARY KEY,
ISBN_10 VARCHAR(10),
TITLE VARCHAR(50),
CATEGORY VARCHAR(25),
PRICE DECIMAL(6,2),
BINDING VARCHAR(2),
PUB_DATE DATE,
AUTHOR_ID SMALLINT,
PUBLISHER_ID SMALLINT
);
2.
ALTER SESSION SET nls_date_format = 'DD-MM-YYYY HH24:MI:SS';
3.
INSERT INTO BOOK
VALUES('4','123459','INTRODUCTION TO SmallTalk','IT',157.00,'S',**'26-01-1991'**,13,103);
It gave an error:
ORA-01843: not a valid month
However if do the following there is no problem:
Query:
INSERT INTO
BOOK
VALUES('4','123459','INTRODUCTION TO Small Talk','IT',157.00,'S','**26-JAN-1991**',13,103);
Can anyone explain why?
You want to read the Datetime Literals section of the manual. Alternatives are:
Use a date literal: DATE '1991-01-26'
Convert from string: TO_DATE('26-01-1991', 'DD-MM-YYYY')
If you set NLS_DATE_FORMAT you can omit TO_DATE()'s second argument but not skip the function entirely.
See also: Datetime Format Models
It worked for me. That implies that your alter statement did not work for some reason. However, it is not good practice to assume a specific date format on a system when using literals. Instead, cast the literal with a format mask on the insert, such as:
INSERT INTO BOOK
VALUES('4','123459','INTRODUCTION TO Small Talk','IT',157.00,'S',
to_date('26-JAN-1991','DD-MON-YYYY'), 13,103);
(or whatever format you require as a literal input value)
This because in your database, nls_date_time is set to 'DD-MON-RRRR' format, you can check this using
select * from V$NLS_PARAMETERS
In this query
INSERT INTO BOOK VALUES('4','123459','INTRODUCTION TO SmallTalk','IT',157.00,'S','26-01-1991',13,103);
date format is 'dd-mm-rrrr', change the statement as
INSERT INTO BOOK VALUES('4','123459','INTRODUCTION TO SmallTalk','IT',157.00,'S',to_date('26-01-1991', 'dd-mm-rrrr'),13,103);
and it will also run since you have now provided the date format.
When you set
ALTER SESSION SET nls_date_format = 'DD-MM-YYYY HH24:MI:SS';
then your insert must match this format, i.e.
INSERT INTO BOOK VALUES('4','123459','INTRODUCTION TO SmallTalk','IT',157.00,'S',
'26-01-1991 00:00:00'
,13,103);
However, the more secure way is to use date literals or TO_DATE function.
You just need to use
INSERT INTO TABLE_NAME VALUES('07-JAN-96');
Oracle always takes "DD-MMM-YY" format. You should write your month as the first 3 characters of month name.

Oracle date format picture ends before converting entire input string

My table has two DATE format attributes, however, when i try to insert value it throws an error: date format picture ends before converting entire input string.
Here is my attempted code:
insert into visit
values(123456, '19-JUN-13', '13-AUG-13 12:56 A.M.');
I think the problem is with 12:56 but Oracle documentation says date implies both date and time.
Perhaps you should check NLS_DATE_FORMAT and use the date string conforming the format.
Or you can use to_date function within the INSERT statement, like the following:
insert into visit
values(123456,
to_date('19-JUN-13', 'dd-mon-yy'),
to_date('13-AUG-13 12:56 A.M.', 'dd-mon-yyyy hh:mi A.M.'));
Additionally, Oracle DATE stores date and time information together.
you need to alter session
you can try before insert
sql : alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'
What you're trying to insert is not a date, I think, but a string. You need to use to_date() function, like this:
insert into table t1 (id, date_field) values (1, to_date('20.06.2013', 'dd.mm.yyyy'));
I had this error today and discovered it was an incorrectly-formatted year...
select * from es_timeexpense where parsedate > to_date('12/3/2018', 'MM/dd/yyy')
Notice the year has only three 'y's. It should have 4.
Double-check your format.

Resources