Replacing specific date with a empty value in Oracle denodo - sql

I have a view where I am selecting a date column and reading it as a local date in denodo. In my column, I have a date '00-Jan-1900' like this which is giving issue so I wanted to replace this with empty.
When I run this query, I get results as shown in the table2. But what I want is just an empty record in place of this date and looking like TABLE3.
Query:
select
to_localdate('dd-MM-yyyy', substring(replace("DATE", '00-Jan-1900', ''), 0, 10)) AS dtm
from XX
Table1:
DATE
22-Dec-2016
00-Jan-1900
30-Sep-2014
After replacing the date i get
Table2:
DATE
0201-12-22
0201-09-30
Is there a way i get output table like this?
TABLE3:
DATE
22-Dec-2016
30-Sep-2014

In my column, I have a date '00-Jan-1900' like this which is giving issue so I wanted to replace this with empty.
In Oracle, you can use:
UPDATE table_name
SET value = NULL
WHERE EXTRACT( DAY FROM value ) = 0;
If you have the table:
CREATE TABLE table_name ( value DATE );
Then, some extra hoops need to be jumped through to insert an invalid date (namely generating the date from binary data so that the normal validation process for date values can be skipped) by creating this function:
CREATE FUNCTION createDate(
year int,
month int,
day int,
hour int,
minute int,
second int
) RETURN DATE DETERMINISTIC
IS
hex CHAR(14);
d DATE;
BEGIN
hex := TO_CHAR( FLOOR( year / 100 ) + 100, 'fm0X' )
|| TO_CHAR( MOD( year, 100 ) + 100, 'fm0X' )
|| TO_CHAR( month, 'fm0X' )
|| TO_CHAR( day, 'fm0X' )
|| TO_CHAR( hour + 1, 'fm0X' )
|| TO_CHAR( minute + 1, 'fm0X' )
|| TO_CHAR( second + 1, 'fm0X' );
DBMS_OUTPUT.PUT_LINE( hex );
DBMS_STATS.CONVERT_RAW_VALUE( HEXTORAW( hex ), d );
RETURN d;
END;
/
Then, you can have the data:
INSERT INTO table_name ( value )
SELECT DATE '1900-01-01' FROM DUAL UNION ALL
SELECT createDate( 1900, 1, 0, 0, 0, 0 ) FROM DUAL;
and:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
SELECT value,
TO_CHAR( value, 'YYYY-MM-DD HH24:MI:SS' ) AS string_value
FROM table_name;
Outputs:
VALUE | STRING_VALUE
:------------------ | :------------------
1900-01-01 00:00:00 | 1900-01-01 00:00:00
1900-01-00 00:00:00 | 0000-00-00 00:00:00
To get rid of your invalid value, you can use:
UPDATE table_name
SET value = NULL
WHERE EXTRACT( DAY FROM value ) = 0;
Then:
SELECT value,
TO_CHAR( value, 'YYYY-MM-DD HH24:MI:SS' ) AS string_value
FROM table_name;
Outputs:
VALUE | STRING_VALUE
:------------------ | :------------------
1900-01-01 00:00:00 | 1900-01-01 00:00:00
null | null
db<>fiddle here
Is there a way i get output table like this?
TABLE3:
DATE
22-Dec-2016
30-Sep-2014
You can use:
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-Mon-YYYY';
And then just run your query and it should change the output (but you will need to make sure the format is set in future sessions when you run the query).
Or you can specify the format model using TO_CHAR:
SELECT TO_CHAR( your_column, 'DD-Mon-YYYY' ) AS your_column
FROM your_table

Related

What would be the best way to filter part of the timestamp?

For example, I have a TIMESTAMP field and a record is something like '2021-04-23 14:17:46' in my database, and I want to find the records that start with '2021-04-23', that is a part of the TIMESTAMP, in SQL. What would be the best way to filter part of the timestamp?
And the other way around? If I have something like '2021-03-04' and I want to find all the timestamps that are yyyy-MM-dd HH: mm: ss
If your parameter is a valid date string, use date arithmetic. For example
-- parameter
with prm as (
select '2021-04-23' pd from dual
),
-- sample data
tbl(Code, Dt) as (
select 'c1', TIMESTAMP '2021-04-23 12:17:46' from dual union all
select 'c2', TIMESTAMP '2021-04-24 14:17:46' from dual
)
--
select tbl.*
from tbl
cross join prm
where dt >= TO_DATE(prm.pd, 'YYYY-mm-DD') and dt < TO_DATE(prm.pd, 'YYYY-mm-DD') + 1
order by code, dt
select dttm_col
from table
where to_date(dttm_col) = '2020-01-20'
The simple way is to TRUNCate the timestamp and compare it to a literal:
SELECT *
FROM table_name
WHERE TRUNC( timestamp_column ) = DATE '2021-04-23'
This may be simple but its not the best solution as Oracle will not use any index on the timestamp_column and will perform a full table scan; to use an index you would need to create a function-based-index on TRUNC( timestamp_column ).
The better way, although slightly more complicated, is to compare on a range of values using a TIMESTAMP literal:
SELECT *
FROM table_name
WHERE timestamp_column >= TIMESTAMP '2021-04-23 00:00:00'
AND timestamp_column < TIMESTAMP '2021-04-23 00:00:00' + INTERVAL '1' DAY;
or, using DATE literals:
SELECT *
FROM table_name
WHERE timestamp_column >= DATE '2021-04-23'
AND timestamp_column < DATE '2021-04-23' + INTERVAL '1' DAY;
If you want to compare to a string, rather than a literal, then use TO_TIMESTAMP:
SELECT *
FROM table_name
WHERE timestamp_column >= TO_TIMESTAMP( '2021-04-23', 'YYYY-MM-DD' )
AND timestamp_column < TO_TIMESTAMP( '2021-04-23', 'YYYY-MM-DD' ) + INTERVAL '1' DAY;
or, to remove the time component:
SELECT *
FROM table_name
WHERE timestamp_column >= TO_TIMESTAMP( SUBSTR( '2021-04-23 14:17:46', 1, 10 ), 'YYYY-MM-DD' )
AND timestamp_column < TO_TIMESTAMP( SUBSTR( '2021-04-23 14:17:46', 1, 10 ), 'YYYY-MM-DD' ) + INTERVAL '1' DAY;

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!!

Help with Sql query for comparing string(HH24MI) to date

We have a configuration table as shown below that stores the start time and the duration.
If the start time is 9:20 pm (3rd one ) add the duration then the time becomes 9:35.
I have to find out if the current time is in between any of the values.
I have to return the output based on the start_time and duration. i.e current time should be between start_time and the start_time + duration. (between 09:20 and and 09:35)
Can you please help me with the sql query or is it better if we go with sql function?
Start_time, duration(minutes) output
1108 5 2
1054 100 5
2120 15 8
I'm not a fan of storing dates and times in VARCHAR2 columns. START_TIME should really be a DATE or a TIMESTAMP column.
That said, you can do something like
with x as (
select '1108' start_time, 5 duration, 2 output from dual
union all
select '1054', 100, 5 from dual
union all
select '2120', 15, 8 from dual
)
select *
from (
select to_date(
to_char(sysdate,'YYYY-MM-DD') || ' ' ||
start_time,
'YYYY-MM-DD HH24MI' ) start_date,
to_date(
to_char(sysdate,'YYYY-MM-DD') || ' ' ||
start_time,
'YYYY-MM-DD HH24MI' ) + duration/24/60 end_date
from x)
where sysdate between start_date and end_date
The following selects all rows where sysdate is within the Start_Time and Start_Time + duration (EDITed as per comment from OP):
SELECT (TRUNC ( SYSDATE ) + TO_NUMBER ( SUBSTR ( Start_Time, 0, 2 ) ) / 24.0 + TO_NUMBER ( SUBSTR ( Start_Time, 3 ) ) / (24.0 * 60.0)) start_date, (TRUNC ( SYSDATE ) + TO_NUMBER ( SUBSTR ( Start_Time, 0, 2 ) ) / 24.0 + TO_NUMBER ( SUBSTR ( Start_Time, 3 ) ) / (24.0 * 60.0) + TO_NUMBER (duration)) end_date FROM configtable;

Extract date (yyyy/mm/dd) from a timestamp in PostgreSQL

I want to extract just the date part from a timestamp in PostgreSQL.
I need it to be a postgresql DATE type so I can insert it into another table that expects a DATE value.
For example, if I have 2011/05/26 09:00:00, I want 2011/05/26
I tried casting, but I only get 2011:
timestamp:date
cast(timestamp as date)
I tried to_char() with to_date():
SELECT to_date(to_char(timestamp, 'YYYY/MM/DD'), 'YYYY/MM/DD')
FROM val3 WHERE id=1;
I tried to make it a function:
CREATE OR REPLACE FUNCTION testing() RETURNS void AS '
DECLARE i_date DATE;
BEGIN
SELECT to_date(to_char(val1, "YYYY/MM/DD"),"YYYY/MM/DD")
INTO i_date FROM exampTable WHERE id=1;
INSERT INTO foo(testd) VALUES (i);
END
What is the best way to extract date (yyyy/mm/dd) from a timestamp in PostgreSQL?
You can cast your timestamp to a date by suffixing it with ::date. Here, in psql, is a timestamp:
# select '2010-01-01 12:00:00'::timestamp;
timestamp
---------------------
2010-01-01 12:00:00
Now we'll cast it to a date:
wconrad=# select '2010-01-01 12:00:00'::timestamp::date;
date
------------
2010-01-01
On the other hand you can use date_trunc function. The difference between them is that the latter returns the same data type like timestamptz keeping your time zone intact (if you need it).
=> select date_trunc('day', now());
date_trunc
------------------------
2015-12-15 00:00:00+02
(1 row)
Use the date function:
select date(timestamp_field) from table
From a character field representation to a date you can use:
select date(substring('2011/05/26 09:00:00' from 1 for 10));
Test code:
create table test_table (timestamp_field timestamp);
insert into test_table (timestamp_field) values(current_timestamp);
select timestamp_field, date(timestamp_field) from test_table;
Test result:
Have you tried to cast it to a date, with <mydatetime>::date ?
In postgres simply :
TO_CHAR(timestamp_column, 'DD/MM/YYYY') as submission_date
This works for me in python 2.7
select some_date::DATE from some_table;
Just do select date(timestamp_column) and you would get the only the date part.
Sometimes doing select timestamp_column::date may return date 00:00:00 where it doesn't remove the 00:00:00 part. But I have seen date(timestamp_column) to work perfectly in all the cases. Hope this helps.
CREATE TABLE sometable (t TIMESTAMP, d DATE);
INSERT INTO sometable SELECT '2011/05/26 09:00:00';
UPDATE sometable SET d = t; -- OK
-- UPDATE sometable SET d = t::date; OK
-- UPDATE sometable SET d = CAST (t AS date); OK
-- UPDATE sometable SET d = date(t); OK
SELECT * FROM sometable ;
t | d
---------------------+------------
2011-05-26 09:00:00 | 2011-05-26
(1 row)
Another test kit:
SELECT pg_catalog.date(t) FROM sometable;
date
------------
2011-05-26
(1 row)
SHOW datestyle ;
DateStyle
-----------
ISO, MDY
(1 row)
You can use date_trunc('day', field).
select date_trunc('day', data_gps) as date_description from some_table;