Covert NVARCHAR to number (digits after decimal sign vary) - sql

Do you know how I can convert NVARCHAR in Oracle if the digits after decimal signs vary?
I need this in order to convert it to date, using this formula:
select to_date('12/30/1899', 'MM/DD/YYYY') + 40676.2641666667
from dual;
The thing is that the digits in the second part (40676.2641666667) vary so I can use to_number(t.column, '99999D9999999999'), because it doesn't work this way.
Do you have any suggestions?

These all work for me:
select (date '1899-12-30') + '40676.2641666667'
from dual
and:
select (date '1899-12-30') + cast('40676.2641666667' as number)
from dual
and:
select (date '1899-12-30') + 40676.2641666667
from dual
One caveat is that internationalization settings might require comma instead of period.

Oracle doesn't have NVARCHAR, it has NVARCHAR2. The following works for me:
DECLARE
nv_Number NVARCHAR2(0032) := 40676.2641666667;
dt_Base DATE := TO_DATE('12/30/1899', 'MM/DD/YYYY');
dt_Result DATE;
BEGIN
dt_Result := dt_Base + TO_NUMBER(nv_Number);
DBMS_OUTPUT.PUT_LINE(TO_CHAR(dt_Result,'yyyymmdd hh24:mi:ss'));
END;
Result: 20110513 06:20:24

Related

Converting decimal to Date

I have a column with dates formatted as decimals, for example: 20,210,830.
I want to convert this number to date format as 08/30/2021
I have tried to use convert and the database shoots me an error that convert is not a valid function. Cast seems to work but, only returns a null value every time.
This statement will validate:
SELECT CAST(CAST(CONTCLMPDTE AS VARCHAR(8)) AS DATE)
FROM CMSFIL.JCTDSC AS COMPLDATE
This statement works but, just outputs null. For background I am querying from a Db2 database.
My ultimate goal is to use this converted date to grab the difference from the current day.
Such as
DAY(CURRENT_DATE) - DAY(COMPLDATE)
Converting it to a date, you cqan do it like this
CREATE TABLE JCTDSC (
CONTCLMPDTE varchar(10)
);
INSERT INTO JCTDSC VALUES ('20,220,830')
SELECT date(to_date(REPLACE(CONTCLMPDTE,',',''),'YYYYMMDD')) FROM JCTDSC AS COMPLDATE
1
2022-08-30
fiddle
So after a long couple days and almost pulling my hair out, here is what worked for me.
SELECT date(substr(CONTCLMPDTE,1,4)||'-'||substr(CONTCLMPDTE,5,2)||'-'||substr(CONTCLMPDTE,7,2)) FROM JCTDSC WHERE COMPANYNUMBER={Company Number} AND JOBNUMBER={Job Number} LIMIT 1
This formatted from yyyymmdd to mm/dd/yyyy. It also worked for finding the days between current_date and CONTCLMPDTE using this code.
DAYS(CURRENT_DATE) - DAYS({COntract Compl Date Formatted})
Thank you all for your help!
You probably get an error because you have some INT / DECIMAL value which can't be converted to a date using this pattern.
The solution is to create some "safe" conversion function "eating" errors like below.
CREATE FUNCTION DATE_SAFE (P_DT INT)
RETURNS DATE
CONTAINS SQL
NO EXTERNAL ACTION
DETERMINISTIC
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
RETURN CAST (NULL AS DATE);
END;
RETURN DATE (TO_DATE (CAST (P_DT AS CHAR (8)), 'YYYYMMDD'));
END
Usage:
SELECT
CONTCLMPDTE
--, DATE (TO_DATE (CAST (CONTCLMPDTE AS CHAR (8)), 'YYYYMMDD'))
, DATE_SAFE (CONTCLMPDTE)
FROM (VALUES 0, 20220830) T (CONTCLMPDTE)
The function returns NULL if the corresponding INT can't be converted to a DATE, and no error is thrown as in case, when you uncomment the commented out line with built-in functions only.
The value just need to be converted into a string with a date format. Then you can use the date() function to convert to date.
create table qtemp/dec_vals (
col1 decimal(8,0) );
insert into qtemp/dec_vals
values (20200830), (20200831), (20200901), (20200902), (20200903), (20200904), (20200905), (20200906);
select date(substr(char(col1), 5, 2) || '/' || substr(char(col1), 7, 2) || '/' || substr(char(col1), 1, 4)) from qtemp/dec_vals;

Receiving ORA-01843: not a valid month error while retrieving data between two dates

I have a column in oracle database table which is Varchar2. In this column I am storing date line 29-1-2021 or 28-12-2020. I want to retrieve data from below query between two dates then I am getting error of Invalid month. How can I resolve this issue ?
SELECT Line_Stop_Id, Function_name, Product_family, line_description, Reason_Category, Reason_detail,
Product_item, product_description, request_raised_date, request_raised_time, cm.EMP_NAME as raised_by, Lse.User_Closer_Description,
Cm1.Emp_Name as Closer_User, Lse.User_Closer_Date, Lse.Final_Closer_Description, Lse.Final_Closer_Date, Lse.Final_Closer_Time,
Cm2.Emp_Name as Final_Closer, Lse.Resource_Effected ,
ROUND(24*(sysdate - to_date(Request_Raised_Date
||' '
||request_raised_time, 'DD-Mon-RR HH24:MI:SS'))) AS TAT
FROM Xx_Lsp_Linestoppage_Entry lse
Left join Emp_Master cm ON Lse.Raised_By = Cm.Emp_No
Left join Emp_Master cm1 ON Lse.Closer_User = Cm1.Emp_No
Left join Emp_Master cm2 ON Lse.Final_Closed_By = Cm2.Emp_No
where TO_DATE(Lse.Request_Raised_Date, 'DD-Mon-RR') Between TO_DATE('01-Jan-21', 'DD-Mon-RR') and TO_DATE('29-Jan-21', 'DD-Mon-RR');
You should check the validity of your date values stored as strings before a conversion and do a cleanup of them (of fix them).
This can be done via, for example, cursor in PL/SQL block (or wrapped in function to export query results or filter by its value):
declare
l_date date;
begin
for r in (
select distinct
request_raised_time
from Xx_Lsp_Linestoppage_Entry
/*To reduce rows in cursor*/
where not regexp_like('^\d{2}-\d{2}-\d{4}')
) loop
begin
l_date := to_date(r.q, 'dd-mm-yyyy');
exception
when others then dbms_output.put_line('Invalid date: ' || r.q);
end;
end loop;
end;
/
db<>fiddle here
Note, that you need to quote dashes inside format to make it exact, because Oracle treats unquoted dash as any symbol from quite wide set of delimiters. So it will process 01/12/2020 as date '2020-12-01', not as invalid date.
select to_date('01/12/2021', 'dd-mm-yyyy') as dt from dual;
DT
--------------------
2021-12-01T00:00:00Z
Elapsed: 00:00:00.002
1 rows selected.
select to_date('01-12-2021', 'dd-mm-yyyy') as dt from dual;
DT
--------------------
2021-12-01T00:00:00Z
Elapsed: 00:00:00.002
1 rows selected.
select to_date('01$12$2021', 'dd-mm-yyyy') as dt from dual;
DT
--------------------
2021-12-01T00:00:00Z
Elapsed: 00:00:00.002
1 rows selected.
You are storing the date in the format 29-1-2020 (dd-mm-yyyy) so use this format in the to_Date
replace
DD-Mon-RR
with
dd-mm-yyyy
Probably being the Lse.Request_Raised_Date field of type varchar2 it contains more information than you need for your query.
I think the best way is to select a string that only identifies the part necessary for the identification of the date using the function:
substr(string , string start from , string lenght )
This is an example:
select to_date(substr('29-01-2021 23:01:55',1,10),'DD-MM-YYYY') from dual;
TO_DATE (SU
----------
29-01-2021
instead of my string '29 -01-2021 23:01:55 ' enter field Lse.Request_Raised_Date
You can use on conversion error:
to_date(Request_Raised_Date || ' ' || request_raised_time
default null on conversion error, 'DD-Mon-YYYY HH24:MI:SS')
This returns NULL instead of an error.
Hopefully, this is a lesson on why you should not store date/time values as strings. You can actually look for the bad values using:
select Request_Raised_Date, request_raised_time
from Xx_Lsp_Linestoppage_Entry
where to_date(Request_Raised_Date || ' ' || request_raised_time
default null on conversion error, 'DD-Mon-YYYY HH24:MI:SS') is null and
Request_Raised_Date is not null
This may give you some ideas on how to fix the data.

ansi SQL date function in Oracle

I realize I could use a combination of to_char and to_date and what not as a work-around, but I'm trying to figure out why this doesn't work. I am using Oracle 12.1
select '2016-10-01'
from dual
union all
select to_char(2016)||'-10-01'
from dual;
Each side of the union produces identical output: 2016-10-01. If I then try to use the ANSI date syntax (as described here: http://blog.tanelpoder.com/2012/12/29/a-tip-for-lazy-oracle-users-type-less-with-ansi-date-and-timestamp-sql-syntax/ ), it only works on the first one, not the second one:
select date '2016-10-01'
from dual
This returns: 10/1/2016
But if I try this:
select date to_char(2016)||'-10-01'
from dual;
I get on:
ORA_00936 missing expression error.
I can code a work-around, but I'm stumped as to why one works and the other does not.
It won't work that way because DATE is not a function but a literal.
The terms literal and constant value are synonymous and refer to a fixed data value.
Date Literals
You can specify a DATE value as a string literal, or you can convert a character or numeric value to a date value with the TO_DATE function. DATE literals are the only case in which Oracle Database accepts a TO_DATE expression in place of a string literal.
You could use TO_DATE function.
select TO_DATE(to_char(2016)||'-10-01', 'YYYY-MM-DD')
from dual;
Rextester Demo
EDIT:
Using dynamic-SQL:
DECLARE
i DATE;
stmt VARCHAR2(100);
BEGIN
stmt := q'{SELECT DATE '}' || TO_CHAR(2016) || '-01-01' || q'{' FROM dual}';
EXECUTE IMMEDIATE stmt INTO i;
DBMS_OUTPUT.PUT_LINE('i =>' || i);
END;

Oracle sql - convert string to date

i am having problems with converting a varchar(yyyymmdd) to date(yyyymmdd).
i have a procedure with a parameter (pdate varchar2, yyyymmdd format) which needed to be converted to date type in yyyymmdd format as well.
so far i tried.
vdate date;
vdate := (to_date(SUBSTR(pdate,1,4)+SUBSTR(pdate,5,2)+SUBSTR(pdate,7,2), 'yyyymmdd'));
this threw a error of ORA-01840: input value not long enough for date format.
any help would be appreciated.
Just use a to_date
select to_date(MyDate, 'yyyymmdd')
from mytable
Test with:
select to_date('20170831','yyyymmdd')
from dual
Also, to concatenate in Oracle, use a double pipe ||
select 'Chicken'||'Food'
from dual
If pdate has other characters after yyyymmdd, and yyyymmdd is in the beginning of the whole text, you can just use
SELECT TO_DATE(SUBSTR(pdate,1,8), 'yyyymmdd')
FROM yourtable;
Example
SELECT TO_DATE(SUBSTR('20170831 10:30am',1,8), 'yyyymmdd')
FROM dual;
Otherwise, you can directly use TO_DATE() as suggested by most that replied

Oracle convert RAW to date format

I have a RAW field in my Oracle database that represents the date of user registered in system.
The value is something like 24E2321A0000000000 However I need convert the value to the date it represents (etc 2008-12-25 15:04:31).
I tried with totimestamp (see this sqlfiddle) but that didn't work.
Maybe this will help:
SELECT utl_raw.cast_to_binary_integer('24E2321A0000000000') raw_to_int
FROM dual
/
Output is 36. I'm not sure if you need days or hours. Next example is about adding 36 hours to SYSDATE:
-- SYSDATE + 36/24 --
SELECT SYSDATE+(utl_raw.cast_to_binary_integer('24E2321A0000000000')/24) my_date
FROM dual
/
MY_DATE
---------------------
12/13/2013 4:29:22 AM
please try one
declare
d date;
begin
dbms_stats.convert_raw_value (hextoraw('7876070A010101'), d);
dbms_output.put_line (d);
end;