Formatting date when using CAST - sql

I would like to use CAST to convert a DATE type to a VARCHAR2 type.
DBUSER >SELECT CAST(CURRENT_DATE AS VARCHAR2(20)) THE_DATE from DUAL;
THE_DATE
--------------------
09-AUG-17
However, I need the VARCHAR2 result to be formatted as 'YYYYMM'. I know that I can achieve this effect by changing the session date format, but I would rather not do that.
DBUSER >ALTER SESSION SET NLS_DATE_FORMAT = 'YYYYMM';
Session altered.
DBUSER >SELECT CAST(CURRENT_DATE AS VARCHAR2(20)) THE_DATE from DUAL;
THE_DATE
--------------------
201708
I would like to avoid using Oracle's proprietary TO_CHAR() function. Does anyone have a suggestion on how to do that?

I am trying to standardize on ANSI SQL to the degree possible and avoid proprietary vendor nonstandard implementations.
There is no function specified in the ANSI SQL92 standard which formats DATETIME datatypes as a string.
The simplest solution is to use the functions Oracle provides for that purpose:
SELECT TO_CHAR( yourdate, 'YYYYMM' ) FROM yourtable;
However, you can get the year and month components using the EXTRACT function (which is in the ANSI standard):
SELECT EXTRACT( YEAR FROM yourdate ),
EXTRACT( MONTH FROM yourdate )
FROM yourtable;
Then you need to convert the numbers to a string and concatenate the strings:
SELECT TO_CHAR( EXTRACT( YEAR FROM yourdate ) )
|| TO_CHAR( EXTRACT( MONTH FROM yourdate ) )
FROM yourtable
but you were trying to avoid TO_CHAR so you could do:
SELECT CAST( EXTRACT( YEAR FROM yourdate ) AS VARCHAR2(4) )
|| CAST( EXTRACT( MONTH FROM yourdate ) AS VARCHAR2(2) )
FROM yourtable
or, using an implicit cast
SELECT EXTRACT( YEAR FROM yourdate )
|| EXTRACT( MONTH FROM yourdate )
FROM yourtable
However, if the year is not 4-digits or the month is not 2-digits then you need to pad the values; again, the simple solution is TO_CHAR:
SELECT TO_CHAR( EXTRACT( YEAR FROM yourdate ), 'FM0000' )
|| TO_CHAR( EXTRACT( MONTH FROM yourdate ), 'FM00' )
FROM yourtable
or LPAD:
SELECT LPAD( EXTRACT( YEAR FROM yourdate ), 4, '0' )
|| LPAD( EXTRACT( MONTH FROM yourdate ), 4, '0' )
FROM yourtable
But neither of those are in the ANSI standard so:
SELECT CASE
WHEN EXTRACT( YEAR FROM yourdate ) < 10 THEN '000'
WHEN EXTRACT( YEAR FROM yourdate ) < 100 THEN '00'
WHEN EXTRACT( YEAR FROM yourdate ) < 1000 THEN '0'
ELSE NULL
END
|| EXTRACT( YEAR FROM yourdate )
|| CASE
WHEN EXTRACT( MONTH FROM yourdate ) < 10 THEN '0'
END
|| EXTRACT( MONTH FROM yourdate )
FROM yourtable;
And we've managed to transform a single Oracle function into a behemoth of an ANSI compatible expression.
But, Oracle's DATE datatype does not comply to the ANSI standard (it is a concatenation of the ANSI DATE and TIME datatypes) so I'll ask whether it is worth it - especially if you then consider displaying the time component of a date (which EXTRACT will not extract unless you first use CAST to convert the DATE to a TIMESTAMP).
SELECT TO_CHAR( yourdate, 'YYYYMMDDHH24MISS' ) FROM yourtable
or
SELECT CASE
WHEN EXTRACT( YEAR FROM yourdate ) < 10 THEN '000'
WHEN EXTRACT( YEAR FROM yourdate ) < 100 THEN '00'
WHEN EXTRACT( YEAR FROM yourdate ) < 1000 THEN '0'
ELSE NULL
END
|| EXTRACT( YEAR FROM yourdate )
|| CASE
WHEN EXTRACT( MONTH FROM yourdate ) < 10 THEN '0'
END
|| EXTRACT( MONTH FROM yourdate )
|| CASE
WHEN EXTRACT( DAY FROM yourdate ) < 10 THEN '0'
END
|| EXTRACT( DAY FROM yourdate )
|| CASE
WHEN EXTRACT( HOUR FROM CAST( yourdate AS TIMESTAMP ) ) < 10 THEN '0'
END
|| EXTRACT( HOUR FROM CAST( yourdate AS TIMESTAMP ) )
|| CASE
WHEN EXTRACT( MINUTE FROM CAST( yourdate AS TIMESTAMP ) ) < 10 THEN '0'
END
|| EXTRACT( MINUTE FROM CAST( yourdate AS TIMESTAMP ) )
|| CASE
WHEN EXTRACT( SECOND FROM CAST( yourdate AS TIMESTAMP ) ) < 10 THEN '0'
END
|| EXTRACT( SECOND FROM CAST( yourdate AS TIMESTAMP ) )
FROM yourtable;
[TL/DR] Just use TO_CHAR

This may be help you:
SELECT extract(year from CURRENT_DATE) || case when extract(month from CURRENT_DATE) <10 THEN '0' || extract(month from CURRENT_DATE) END THE_DATE from DUAL;

Related

How to unite two columns of date + time for datediff - Oracle sql

I have two int columns:
thedate - for example 20210512
thetime - for example 142342
So, i need to unite them to one column to check if the time difference is lower the 5.
I tried this:
TO_DATE(sysdate) - TO_DATE(thedate, 'YYYY-MM-DD') < 5
But it only for the date not for the time so i will be glad to know how to unite the two int columns + and convert it to date type for time difference.
You can use:
SELECT *
FROM table_name
WHERE TO_DATE( thedate * 1000000 + thetime, 'YYYYMMDDHH24MISS' ) > SYSDATE - 5;
Which, for the sample data:
CREATE TABLE table_name ( thedate INT, thetime INT );
INSERT INTO TABLE_NAME ( thedate, thetime ) VALUES (
TO_NUMBER( TO_CHAR( SYSDATE, 'YYYYMMDD' ) ),
TO_NUMBER( TO_CHAR( SYSDATE, 'HH24MISS' ) )
);
INSERT INTO TABLE_NAME ( thedate, thetime ) VALUES (
TO_NUMBER( TO_CHAR( SYSDATE - INTERVAL '4 23' DAY TO HOUR, 'YYYYMMDD' ) ),
TO_NUMBER( TO_CHAR( SYSDATE - INTERVAL '4 23' DAY TO HOUR, 'HH24MISS' ) )
);
INSERT INTO TABLE_NAME ( thedate, thetime ) VALUES (
TO_NUMBER( TO_CHAR( SYSDATE - INTERVAL '5 1' DAY TO HOUR, 'YYYYMMDD' ) ),
TO_NUMBER( TO_CHAR( SYSDATE - INTERVAL '5 1' DAY TO HOUR, 'HH24MISS' ) )
);
Outputs:
THEDATE
THETIME
20210512
131832
20210507
141832
Or, if you want to use indexes on the thedate and thetime columns (the query above would not use indexes on thedate and thetime columns but would require a function-based index) then:
SELECT *
FROM table_name
WHERE thedate > TO_NUMBER( TO_CHAR( SYSDATE - 5, 'YYYYMMDD' ) )
OR ( thedate = TO_NUMBER( TO_CHAR( SYSDATE - 5, 'YYYYMMDD' ) )
AND thetime >= TO_NUMBER( TO_CHAR( SYSDATE - 5, 'HH24MISS' ) )
)
However, the better solution is to use appropriate data-types for your data; in this case, you should store date values in a DATE data-type (which, in Oracle, contains year-second components) rather than as two INT values for date and time.
db<>fiddle here
You want to convert to a timestamp, not a date. So:
select to_timestamp(cast(20210512 * 1000000 + 142342 as varchar2(255)), 'YYYYMMDDHH24MISS')
from dual;
Here is a db<>fiddle showing that this works.
Or in a where clause:
to_timestamp(cast(thedate * 1000000 + thetime as varchar2(255)), 'YYYYMMDDHH24MISS') > sysdate - interval '5' day
(or whatever you mean by "5").
Note: You may want to add a computed column to the table that has the full timestamp:
alter table t add column timestamp generated always as
( to_timestamp(cast(thedate * 10000 + thetime as varchar2(255)), 'YYYYMMDDHH24MISS') );

Validation of first 6 digits in a SQL query in Oracle SQL developer

There is a requirement where I need to validate the identity card number with the first 6 digits as DOB. I need to find out the users not maintaining correct format.
If the dob is 02/10/1983 - 83021023456 && if its 02/10/2083 ->83221023456 (DOB is in MM/DD/YYYY and if year of birth >2000 then the +20 is done to the dob month). The query I tried with is given below:-
SELECT f_account_name,F_SSN ,F_DOB from table where
CASE WHEN SUBSTR(to_char(F_DOB, 'YYYY-MM-DD'),0,4)>2000
THEN
SUBSTR(f_ssn,0,6) <>
SUBSTR(to_char(F_DOB, 'YY-MM-DD'),0,2)
||SUBSTR(to_char(F_DOB, 'YY-MM-DD'),4,2)
||SUBSTR(to_char(F_DOB, 'YY-MM-DD'),7,2)
ELSE
SUBSTR(f_ssn,0,6) <>
SUBSTR(to_char(F_DOB, 'YY-MM-DD'),0,2)
||(SUBSTR(to_char(F_DOB, 'YY-MM-DD'),4,2)+20)
||SUBSTR(to_char(F_DOB, 'YY-MM-DD'),7,2)
END;
Its not working .
You cannot have the comparison inside the CASE expression; since the left-hand side of the expression is identical then it is simple to move it out and then you can simplify the rest:
SELECT f_account_name,
F_SSN,
F_DOB
FROM table_name
WHERE SUBSTR(f_ssn,0,6) !=
CASE
WHEN EXTRACT( YEAR FROM F_DOB ) > 2000
THEN TO_CHAR( F_DOB, 'YYMMDD')
ELSE TO_CHAR( F_DOB, 'YY' )
|| TO_CHAR( EXTRACT( MONTH FROM F_DOB )+20, 'FM00' )
|| TO_CHAR( F_DOB, 'DD')
END;
or, if the rule is to add 20 to the month for each century past 1900 (i.e. 20XX add 20 and 21XX add 40, etc.) then:
SELECT f_account_name,
F_SSN,
F_DOB
FROM table_name
WHERE SUBSTR(f_ssn,0,6) !=
TO_CHAR( F_DOB, 'YY' )
|| TO_CHAR(
EXTRACT( MONTH FROM F_DOB )
+ 20 * GREATEST( TRUNC( EXTRACT( YEAR FROM F_DOB ) / 100 ) - 19, 0 ),
'FM00'
)
|| TO_CHAR( F_DOB, 'DD');
I tried some date arithmetics and worked with numbers rather than strings ...
WITH
-- your input
indata(f_account_name,f_ssn,f_dob) AS (
--string -- number -- string
SELECT 'Arthur',83021023456,'02/10/1983' FROM dual
UNION ALL SELECT 'Tricia',83221023456,'02/10/2083' FROM dual
)
SELECT
f_account_name
, f_ssn
, f_dob
FROM indata
WHERE CAST(TRUNC(f_ssn/100000) AS NUMBER(6))
-- ^ integer division by 100000 to get the first 6 digits ...
= MOD(EXTRACT(YEAR FROM TO_DATE(f_dob,'MM/DD/YYYY')),100) * 10000
-- ^ modulo year of date of 100 gives 3rd and 4th digit of year
+ (
EXTRACT(MONTH FROM TO_DATE(f_dob,'MM/DD/YYYY'))
+CASE
WHEN EXTRACT(YEAR FROM TO_DATE(f_dob,'MM/DD/YYYY')) >= 2000 THEN 20
ELSE 0
END
) * 100
+ EXTRACT(DAY FROM TO_DATE(f_dob,'MM/DD/YYYY'))
;

Convert Oracle Date into RFC 3339 Format

I have a date field in oracle which returns
17-APR-19 12:00:00 AM
I also have a time column (VARCHAR) which returns HHMM in Military
1810
I'd like to combine these two fields to create a timestamp that is formatted to RFC 3339 standards. Preferable like this.
2019-04-17T18:10:00Z
I can convert a timestamp into the correct time using this:
SELECT
TO_CHAR(
SYSTIMESTAMP AT TIME ZONE 'UTC',
'yyyy-mm-dd"T"hh24:mi:ss"Z"'
)
FROM dual;
Is there a way to convert my date and time field into this timestamp format? The time on the date field is incorrect and needs to be replaced by the time field.
You can TRUNCate your date back to midnight and then use NUMTODSINTERVAL to add hours and minutes to it to get the correct time component:
Oracle Setup:
CREATE TABLE your_table ( your_date_column, your_time_column ) AS
SELECT DATE '2019-04-17', '1810' FROM DUAL
Query:
SELECT TO_CHAR(
TRUNC( your_date_column )
+ NUMTODSINTERVAL( SUBSTR( your_time_column, 1, 2 ), 'HOUR' )
+ NUMTODSINTERVAL( SUBSTR( your_time_column, 3, 2 ), 'MINUTE' ),
'YYYY-MM-DD"T"HH24:MI:SS"Z"'
) AS combined_date_time
FROM your_table
Output:
| COMBINED_DATE_TIME |
| :------------------- |
| 2019-04-17T18:10:00Z |
db<>fiddle here
If you want the value as a TIMESTAMP WITH TIME ZONE then:
SELECT CAST(
TRUNC( your_date_column )
+ NUMTODSINTERVAL( SUBSTR( your_time_column, 1, 2 ), 'HOUR' )
+ NUMTODSINTERVAL( SUBSTR( your_time_column, 3, 2 ), 'MINUTE' )
AS TIMESTAMP
) AT TIME ZONE 'UTC' AS combined_date_time
FROM your_table
Just do a bit of string concatenation
to_char( your_date, 'yyyy-mm-dd' ) ||
'T' ||
substr( your_time, 1, 2 ) ||
':' ||
substr( your_time, 3, 2 ) ||
':00Z'
assuming that your_time is always 4 characters long (i.e. 2 AM is represented as the string '0200' rather than '200'). This also assumes that the seconds will always be '00'.
You can achieve this by converting your_number into minutes and add it to your date, then cast it to timestamp as following:
SELECT CAST(
your_date +
(FLOOR(YOUR_TIME/100)*60 + MOD(YOUR_TIME,100)) / 1440
AS TIMESTAMP
) AT TIME ZONE 'UTC' AS YOUR_TIME_STAMP
FROM your_table;
Cheers!!

get the date along with year and month

The date condition below is good for fetching current year and current month I would like to add current date to it ,please append the query to get current date .
If (( Extract ( Month, current_date )) = 1)
Then ( Cast ( ( Cast((( Extract (Year, current_date) -1)), varchar(4)) || '12'), int) )
Else ( If ((Extract ( Month, current_date) -1) < 10 )
Then ( Cast(( ( Cast ((Extract ( Year, current_date )), varchar(4))) || '0' || ( Cast (( Extract ( Month, current_date) - 1), varchar(2)))), int) )
Else ( Cast (( Cast ((Extract ( Year, current_date )), varchar(4)) || ( Cast(( Extract ( Month, current_date) - 1), varchar(2)))), int) )
)
thanks in advance
Your code is Cognos right? I can't help you there, but in DB2, this will get you current year, current month and current date.
values (year(current date), month(current date), current date)
e.g. it will return
1 2 3
---- - ----------
2018 3 2018-03-21

how to get today date in YYYYMMDD in firebird

how to get today date in YYYYMMDD in firebird, I had a look on following but could not figured how to write this.
I think you can do:
select replace(cast(cast('Now' as date) as varchar(10)), '-', '')
from rdb$database
IN FIREBIRD v2.5.5:
SELECT LPAD( EXTRACT( YEAR FROM CURRENT_TIMESTAMP ), 4, '0' ) ||
LPAD( EXTRACT( MONTH FROM CURRENT_TIMESTAMP ), 2, '0' ) ||
LPAD( EXTRACT( DAY FROM CURRENT_TIMESTAMP ), 2, '0' ) || ' ' ||
LPAD( EXTRACT( HOUR FROM CURRENT_TIMESTAMP ), 2, '0' ) ||
LPAD( EXTRACT( MINUTE FROM CURRENT_TIMESTAMP ), 2, '0' ) ||
LPAD( TRUNC( EXTRACT( SECOND FROM CURRENT_TIMESTAMP ) ), 2, '0' )
FROM rdb$database
OUTPUT IS: YYYYMMDD HHMMSS
This is a fully version (in Integer)
select Extract(year FROM cast('NOW' as date))*10000 +
Extract(month FROM cast('NOW' as date))*100 +
Extract(day FROM cast('NOW' as date)) from rdb$database
This is a fully version (in VARCHAR)
select CAST(Extract(year FROM cast('NOW' as date))*10000 +
Extract(month FROM cast('NOW' as date))*100 +
Extract(day FROM cast('NOW' as date)) AS VARCHAR(8)) from rdb$database
This Should work.
CREATE TABLE tab( t time, d date, ts timestamp );
INSERT INTO tab(t,d,ts) VALUES ('14:59:23', '2007-12-31', '2007-12-31 14:59');
SELECT CAST(CAST(d as varchar(10)))
FROM tab;