Reputation: 409
I am trying to set a datetime one second less than the end_ts datetime with sql as below
UPDATE Table1 SET
UPDTD_DT=(SELECT TO_DATE(END_TS-1/(24*60*60),'DD/MM/YYYY HH24:MI:SS')
FROM View1) WHERE id = '123';
But after ran this update, the datetime is 00:00:00. I displayed and checked the TO_DATE(END_TS-1/(246060),'DD/MM/YYYY HH24:MI:SS') which looks fine.
SELECT TO_DATE(END_TS-1/(24*60*60),'DD/MM/YYYY HH24:MI:SS') FROM View1 is 25/03/2022 10:14:44
Any advice would be highly appreciated.
Upvotes: 0
Views: 342
Reputation: 168041
NEVER use TO_DATE
on a value that is already a DATE
(or TIMESTAMP
). At best, it will do nothing and, at worst, it will raise an exception or, as you are finding, give an unexpected output.
You want:
UPDATE Table1
SET UPDTD_DT = (SELECT END_TS - INTERVAL '1' SECOND FROM View1)
WHERE id = '123';
Or 1/(24*60*60)
instead of INTERVAL '1' SECOND
, but the latter is probably easier to comprehend what you mean during a code review.
If you use:
SELECT TO_DATE(END_TS-1/(24*60*60),'DD/MM/YYYY HH24:MI:SS')
FROM View1
and END_TS
is a DATE
column then TO_DATE
expects a string as its first argument so your DATE
value will be implicitly cast to a string using the default format model for date-to-string conversions (the NLS_DATE_FORMAT
session parameter) before being converted back to a DATE
and the query is effectively:
SELECT TO_DATE(
TO_CHAR(
END_TS-1/(24*60*60),
(SELECT value FROM NLS_SESSION_PARAMETERS WHERE parameter = 'NLS_DATE_FORMAT')
),
'DD/MM/YYYY HH24:MI:SS'
)
FROM View1
If the NLS_DATE_FORMAT
does not match the 'DD/MM/YYYY HH24:MI:SS'
format model then you will get an exception. If it does match but does not display the time component (i.e. the NLS_DATE_FORMAT
is DD/MM/YYYY
) then the default time component of midnight will be used.
Theoretically, you could solve the problem by changing the user's NLS_DATE_FORMAT
session parameter:
ALTER SESSION SET NLS_DATE_FORMAT = 'DD/MM/YYYY HH24:MI:SS';
But then you would need to set it for every user who runs the query and users can change their own session parameters at any time so you would have to ensure it is set each time you run the query. So this is not considered good practice.
It is considered better practice to not use TO_DATE
to a DATE
value and avoid the implicit cast to a string.
Upvotes: 6
Reputation: 18675
Reason that is happening is that you're doing a TO_DATE
on a column of type DATE
. There is no need to do that.
Check the following example (the wrapping TO_CHAR is only for display purposes):
SELECT TO_CHAR(
TO_DATE(sysdate-1/(24*60*60),'DD/MM/YYYY HH24:MI:SS'),
'DD-MON-YYYY HH24:MI') as unneeded_todate,
TO_CHAR(
sysdate-1/(24*60*60),
'DD-MON-YYYY HH24:MI') as correct_code
FROM dual;
UNNEEDED_TODATE CORRECT_CODE
-------------------------- --------------------------
12-JUN-2023 00:00 12-JUN-2023 08:06
So, to fix your issue:
UPDATE Table1 SET
UPDTD_DT=(SELECT END_TS-1/(24*60*60)
FROM View1) WHERE id = '123';
Or... use INTERVAL
to add/substract.
UPDATE Table1
SET
UPDTD_DT= (SELECT END_TS - INTERVAL '1' SECOND
FROM View1)
WHERE id = '123';
Upvotes: 4