Subtract number of days from sysdate using variable oracle trigger - oracle

I am creating a trigger to perform an insert in with a date in the past.
days_trans := dbms_random.value(14,90);
time_avail := sysdate - interval ':days_trans' day;
This gives me
PLS-00166: bad format for date, time, timestamp or interval literal
How should I subtract the variable constant?

You cannot bind variables to literals. INTERVAL are used with TIMESTAMP, use either
time_avail := sysdate - days_trans;
or
time_avail := systimestamp - days_trans * interval '1' day;

Related

Adding fractional part to a TIMESTAMP

How can I add the fractional part to a TIMESTAMP. I tried this and it didn't seem to work.
CREATE TABLE t(A TIMESTAMP);
INSERT INTO t(A) VALUES (
DATE '2022-04-01' + INTERVAL '18:02:42.123456' HOUR TO SECOND);
SELECT * from t;
A
01-APR-22 06.02.42.000000 PM
Try
INSERT INTO t(A) VALUES (
TIMESTAMP '2022-04-01 00:00:00' + INTERVAL '18:02:42.123456' HOUR TO SECOND);
When you add in INTERVAL to a DATE then the result is converted to DATE which does not support fractional seconds, see Datetime/Interval Arithmetic

how can we change one date format to another format in oracle sql? ORA-01861

How can we change the date format from DD-MON-YYYY to this format YYYY-MM-DD.
I have a date type column in a table. I want to display that value of that date column in this format - YYYY-MM-DD.
I tried with this -
disp_date := to_char(to_date(disp_date,'dd-mm-rrrr'),'rrrr-mm-dd')
and
disp_date := to_char(to_date(disp_date,'dd-mm-yyyy'),'yyyy-mm-dd')
While executing the above I got an error message stating that:
ORA-01861 Literal does not match format string
Please note the below details of my system,
select value from v$nls_parameters where parameter = 'NLS_DATE_LANGUAGE';
--AMERICAN
select value from v$nls_parameters where parameter = 'NLS_DATE_FORMAT';
--DD-MON-RRRR
If column's datatype is DATE - which is what your sentence suggests:
I have a date type column in a table
then you don't to_date it - it already is a date. Just apply to_char with desired format mask, e.g.
select to_char(disp_date, 'yyyy-mm-dd') from your_table
If you want to change the default display format then run
alter session set nls_date_format = 'YYYY-MM-DD';
select disp_date from ...
Note, your client application may change the format again according to settings in this client application.
A date does not have a format - it is stored internally to the database as a binary value using 7-bytes (representing century, year-of-century, month, day, hour, minute and second). It is not until whatever user interface you are using (i.e. SQL/Plus, SQL Developer, Java, etc.) tries to display it to you, the user, that is is converted it into something you would find meaningful (usually a string) that the date is formatted (and that conversion is done by the user interface and not by the database).
How can we change one date format to another format in oracle?
Since a date does not have a format then this question does not make sense.
If instead, you ask:
How can we display a date in a format in oracle?
If you want to display the date with a specific format then you want to explicitly convert it from a date to a string using TO_CHAR (rather than relying on an implicit conversion by the user interface). Since it is already a DATE then you do not need to use TO_DATE on it and can just use:
DECLARE
date_value DATE := SYSDATE;
formatted_date VARCHAR2(10);
BEGIN
formatted_date := TO_CHAR(date_value, 'yyyy-mm-dd');
DBMS_OUTPUT.PUT_LINE( formatted_date );
END;
/
Now, if your disp_date variable is a string (and not a date) then your code works:
DECLARE
disp_date VARCHAR2(11) := TO_CHAR(SYSDATE, 'DD-MON-RRRR');
BEGIN
disp_date := TO_CHAR(TO_DATE(disp_date, 'DD-MON-RRRR'), 'yyyy-mm-dd');
DBMS_OUTPUT.PUT_LINE( disp_date );
END;
/
db<>fiddle here

Fetch Hours from Created date

I'm just trying to fetch Hour of my table from created date in Oracle 12c Database but it is showing error INVALID EXTRACT FIELD FOR EXTRACT FIELD. kindly guide me to fetch hour of my date my code is here...
SELECT
EXTRACT( HOUR FROM (TO_CHAR(CREATED_DATE,'RRRR-MM-DD HH:MI:SS')) ) HOUR
FROM
INVOICE_V;
my Date is stored as 6/1/2020 4:04:50 PM in this format and Extract function is not accept this function.
Do not store dates as strings.
But, since you have, convert it from a string to a date using TO_DATE:
SELECT EXTRACT( HOUR FROM TO_TIMESTAMP(CREATED_DATE,'DD/MM/YYYY HH12:MI:SS AM') ) AS HOUR
FROM INVOICE_V;
If, however, you meant that its just displaying in that format (and is actually a DATE data type) then CAST the date to a timestamp:
SELECT EXTRACT( HOUR FROM CAST( CREATED_DATE AS TIMESTAMP) ) AS HOUR
FROM INVOICE_V;
An hour can not be used in the EXTRACT function.
The only way to extract hour is to use TO_CHAR or subtract it from TRUNC date as follows:
TO_CHAR(created_date,'HH24') -- OR 'HH' as per your requirement
-- OR
FLOOR(24*(created_date- TRUNC(created_date)))
Please note that Oracle does not store dates in any format. It has its own binary representation. What you see while selecting from the table is based on the NLS_DATE_FORMAT parameter.
You can set it according to your requirement.
ALTER SESSION SET NLS_dATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'; -- like this
If you have a date column (or the-like), then:
select extract(hour from cast(created_date as timestamp)) as hr
from invoice_v
Alternatively:
select to_char(created_date, 'hh24') as hr
from invoice_v
The first expression returns an integer number, while the second produces a string.
Note that hour is a language keyword, hence not a good choice for an identifier (here, you used it as a column alias). I changed that.

Oracle - Date comparison with SYSDATE

I need to compare date with date of current day, using SYSDATE, something like this:
SELECT * FROM my_table
WHERE date_column BETWEEN TO_DATE(SYSDATE -3,'dd.mm.yyyy') AND TO_DATE(SYSDATE,'dd.mm.yyyy');
However, this produces no result....My question :
Based on accepted answer here we should NEVER EVER compare strings with date. But in other side, a SYSDATE is allready a Date data type, and we should not compare It to a date - see here.
If I replace TO_DATE with TO_CHAR in upper SQL things go working again. But TO_CHAR function converts into String, so Oracle (I pressume) needs to convert this string again to date so you force Oracle to do an implicit data type conversion.
So, what should be a correct comparison with date and SYSDATE, in order to avoid Oracle working a bit slowly ?
You should not need to call either TO_DATE or TO_CHAR:
SELECT *
FROM my_table
WHERE date_column >= TRUNC(SYSDATE - 3) AND date_column < TRUNC(SYSDATE + 1);
Assuming date_column is a date type, you should be able to directly compare it against SYSDATE, or SYSDATE offset by some number of days.

timezone-dependant systimestamp and timestamp comparison on Oracle

I've run into a weird situation. Could someone explain why comparison between timestamp and timestamp behaves as below (it depends on session timezone...). In addition outputed values are identical in all cases.
It looks like timestamp inherits timezone from the session for comparison purposes, but for printing it does not?
Queries:
alter session set time_zone = '-6:0';
select cast(systimestamp as timestamp), systimestamp, case when cast(systimestamp as timestamp) < systimestamp then 'timestamp < systm' else 'timestamp >= systm' end as cmp from dual;
alter session set time_zone = '1:0';
select cast(systimestamp as timestamp), systimestamp, case when cast(systimestamp as timestamp) < systimestamp then 'timestamp < systm' else 'timestamp >= systm' end as cmp from dual;
output:
CAST(SYSTIMESTAMPASTIMESTAMP) SYSTIMESTAMP CMP
----------------------------- ----------------------------------- ------------------
14/02/06 21:22:05,319973000 14/02/06 21:22:05,319973000 -06:00 timestamp >= systm
session SET altered.
CAST(SYSTIMESTAMPASTIMESTAMP) SYSTIMESTAMP CMP
----------------------------- ----------------------------------- ------------------
14/02/06 21:22:06,057183000 14/02/06 21:22:06,057183000 -06:00 timestamp < systm
Database is in -6 timezone. Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
Look at this:
https://docs.oracle.com/cd/B12037_01/server.101/b10749/ch4datet.htm#1006334
When you compare date and timestamp values, Oracle converts the data to the more precise datatype before doing the comparison. For example, if you compare data of TIMESTAMP WITH TIME ZONE datatype with data of TIMESTAMP datatype, Oracle converts the TIMESTAMP data to TIMESTAMP WITH TIME ZONE, using the session time zone.
The order of precedence for converting date and timestamp data is as follows:
1. DATE
2. TIMESTAMP
3. TIMESTAMP WITH LOCAL TIME ZONE
4. TIMESTAMP WITH TIME ZONE
For any pair of datatypes, Oracle converts the datatype that has a smaller number in the preceding list to the datatype with the larger number.
SYSTIMESTAMP returns a TIMESTAMP WITH TIME ZONE datatype. Looks like Oracle converts the TIMESTAMP to an TIMESTAMP WITH TIME ZONE datatype for comparison, actualy Oracle performs this:
SELECT
CASE
WHEN CAST(CAST(SYSTIMESTAMP AS TIMESTAMP) AS TIMESTAMP WITH TIME ZONE) < SYSTIMESTAMP
THEN 'timestamp < systm'
ELSE 'timestamp >= systm'
END AS cmp
FROM dual;
For conversion it takes the SESSION Timezone, you can check it with this query:
SELECT
EXTRACT(TIMEZONE_HOUR FROM CAST(CAST(SYSTIMESTAMP AS TIMESTAMP) AS TIMESTAMP WITH TIME ZONE)) AS TZ_HOUR
FROM dual;
You can discuss if this makes sense or not. For a correct conversion you better use FROM_TZ function, then it is under your control. SYSTIMESTAMP returns timestamp in DB timezone, so proper statement would be this one:
SELECT FROM_TZ(LOCALTIMESTAMP, DBTIMEZONE), SYSTIMESTAMP,
CASE FROM_TZ(LOCALTIMESTAMP, DBTIMEZONE) < SYSTIMESTAMP THEN
...

Resources