How to convert time to number in Oracle SQL - oracle

I have a column with time datatype like for example:
01:00
24:00
03:00
I need to convert this time to number so it will be like
0100
2400
0300

First, Oracle does not have a "time" datatype. If you are working with a date or a timestamp datatype, you can use the TO_CHAR function to format the time portion of the data in whatever style you want. The following would return the style you describe, using HH24 to convert hours to the hour format and MI to return the minutes:
TO_CHAR(date_column,'HH24MI')
For example:
select to_char(sysdate,'HH24MI') from dual;
TO_CHAR(SYSDATE,'HH24MI')
-------------------------
0331
Elapsed: 00:00:00.007
1 rows selected.
select to_char(systimestamp,'HH24MI') from dual;
TO_CHAR(SYSTIMESTAMP,'HH24MI')
------------------------------
0331
Elapsed: 00:00:00.006
1 rows selected.

Well, looking at what you posted, if values that column contains look exactly like that, then it is one of CHAR family datatypes because there's no TIME datatype in Oracle, as pmdba already told you. It would certainly help if you explained it properly, instead of letting us guess.
Anyway: if that's so and if values really are stored that way:
SQL> create table test as
2 select '01:00' col from dual union all
3 select '24:00' from dual union all
4 select '03:00' from dual;
Table created.
SQL> desc test
Name Null? Type
----------------------------------------- -------- ---------------------------
COL CHAR(5)
then you'd just have to remove the colon:
SQL> select col, replace(col, ':', '') result
2 from test;
COL RESULT
----- ----------
01:00 0100
24:00 2400
03:00 0300
SQL>
As I said: explain it properly.

Related

Charts in Oracle Apex

Hi everyone I wanna ask u about how I can bring data last 24 hours into bar charts, is there any methods to make it please
I have this table without data
datetime
clientchannel
servicename
service_count
13_02_2022 9:35
*****
notification
2
It is a WHERE clause you need, I presume. Something like this:
select ...
from your_table
where datetime >= sysdate - 1;
Why? Because - when you subtract a number from DATE datatype value in Oracle - it subtracts that many days.
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> select sysdate right_now,
2 sysdate - 1 yesterday
3 from dual;
RIGHT_NOW YESTERDAY
------------------- -------------------
13.02.2022 11:01:34 12.02.2022 11:01:34
SQL>
If you store date values as strings (which means that DATETIME column is declared as e.g. VARCHAR2(20), and that's really bad idea), then you first have to convert it to a valid date datatype value - use TO_DATE function with appropriate format mask:
where to_date(datetime, 'dd_mm_yyyy hh24:mi') >= sysdate - 1
[EDIT] If you want to go 60 minutes back, then subtract that many minutes:
SQL> select sysdate right_now,
2 sysdate - interval '60' minute an_hour_ago
3 from dual;
RIGHT_NOW AN_HOUR_AGO
------------------- -------------------
14.02.2022 07:09:30 14.02.2022 06:09:30
SQL>

string to timestamp conversion plsql

I've inherited some data from an external source which is a timestamp. This was put into warehouse by someone as a varchar2. I need to convert this to a legitimate timestamp but am unsure how. This is how the string looks. "2021-04-23T11:02:17.00Z".
Would appreciate some help.
PS Ideally, I'd also like to know how to trunc this to a more traditional date format of DD-MMM-YYYY e.g. 21-Jan-2021 or even DD-MM-YYYY is fine.
Use to_timestamp_tz() to get the corresponding timstamp with time zone, convert it to the timezone you want it in (for example sessiontimezone) with AT TIME ZONE and cast() that to a timestamp.
SELECT cast(to_timestamp_tz('2021-04-23T11:02:17.00Z', 'YYYY-MM-DD"T"HH24:MI:SS.FF2:TZR') AT TIME ZONE sessiontimezone AS timestamp)
FROM dual;
db<>fiddle
Shouldn't be too difficult. Extract the "date" part, apply TO_DATE function to it (with appropriate format mask) and - that's all. It means that you should "stop" at the date_value in the following query. The last, final_result is a string again, just formatted as you wanted.
SQL> with test (col) as
2 (select '2021-04-23T11:02:17.00Z' from dual)
3 select substr(col, 1, 10) string,
4 --
5 to_date(substr(col, 1, 10), 'yyyy-mm-dd') date_value,
6 --
7 to_char(to_date(substr(col, 1, 10), 'yyyy-mm-dd'), 'dd-mm-yyyy') final_result
8 from test;
STRING DATE_VALUE FINAL_RESU
---------- ---------- ----------
2021-04-23 2021-04-23 23-04-2021
SQL>
In order to avoid that "operation", you might even create a view. For example:
This is a table you currently have:
SQL> create table test as
2 (select 1 id, 'Littlefoot' name, '2021-04-23T11:02:17.00Z' col from dual);
Table created.
Create a view, re-using code I posted above:
SQL> create or replace view v_test as
2 select id, name,
3 to_date(substr(col, 1, 10), 'yyyy-mm-dd') col
4 from test;
View created.
Select from it:
SQL> select * from v_test;
ID NAME COL
---------- ---------- ----------
1 Littlefoot 2021-04-23
Want another format? No problem:
SQL> alter session set nls_date_format = 'dd-mon-yyyy';
Session altered.
SQL> select * from v_test;
ID NAME COL
---------- ---------- -----------
1 Littlefoot 23-apr-2021
SQL>
Or, apply TO_CHAR to view's col column (also demonstrated in code I posted first; see the final_result).
You can use the TO_TIMESTAMP function to do this.
Try:
TO_TIMESTAMP('2021-04-23T11:02:17.00Z', 'YYYY-MM-DDTHH:MI:SS')
You can read more about this function in their Documentation

Error: ORA-01848: day of year must be between 1 and 365 (366 for leap year) while extracting month and year from DateColumn(varchar(10))

SELECT TO_CHAR(TO_DATE(Column_d, 'dd/mm/yyyy'), 'YYYY-MM') as Date_y FROM Table_d
Even want to get quarter from the same date which is again giving me the error ORA-01848 like
SELECT (CASE WHEN (TO_CHAR(TO_DATE(Column_d, 'dd/mm/yyyy'), 'mm')) IN ('01','02','03') THEN 'Q1'
WHEN (TO_CHAR(TO_DATE(Column_d, 'dd/mm/yyyy'), 'mm')) IN ('04','05','06') THEN 'Q2'
WHEN (TO_CHAR(TO_DATE(Column_d, 'dd/mm/yyyy'), 'mm')) IN ('07','08','09') THEN 'Q3'
ELSE 'Q4' END as QTR
FROM Table_d
The way I see it, nothing of what you posted returns ORA-01848. It is - usually, if not always - related to the DDD date format mask which represents day number within the year.
For example, this is correct, as day number 001 equals the 1st of January:
SQL> select to_date('001-2020', 'ddd-yyyy') from dual;
TO_DATE('0
----------
01.01.2020
This returns ORA-01848 as there's no day 405 in this (nor any) year:
SQL> select to_date('405-2020', 'ddd-yyyy') from dual;
select to_date('405-2020', 'ddd-yyyy') from dual
*
ERROR at line 1:
ORA-01848: day of year must be between 1 and 365 (366 for leap year)
So: if you're doing anything like this, make sure that stored values are correct; I presume that not all of them are.
Besides, that's what happens when people store dates as strings into VARCHAR2 (instead of DATE datatype) columns. I'm not saying that you're the cause, but you certainly are a victim here.
[EDIT]
Julian date, eh? In a comment, you said that you used such a query:
Select TO_CHAR(TO_DATE(Julian_dateColumn+1900000, 'YYDDD'), 'YYDDD'), 'DD/MM/YYYY') as column_d from sometable
I doubt it as it is invalid (I suppose you have superfluous , 'YYDDD')).
Anyway, I have no idea why you tried to "convert" Julian date in such a manner. There's a simple and correct way to do so. Here's how:
This is today's date (21.05.2020) presented as Julian date:
SQL> select to_char(sysdate, 'j') julian from dual;
JULIAN
-------
2458991
That's kind of values you have stored in the table. In order to convert it to format you wanted (yyddd), you'd
SQL> select to_char(to_date(2458991, 'j'), 'yyddd') as column_d from dual;
COLUM
-----
20142
I suggest you use this instead of code you currently have, i.e.
SQL> create or replace view table_d as
2 select to_char(to_date(julian_datecolumn, 'j'), 'yyddd') as column_d
3 from sometable;
View created.
SQL> select * From table_d;
COLUM
-----
20142
SQL>

Insert Birthdate with only YY format for period before 2000 Oracle DB

I have afile where i recieve Birthdates and insert them into my Database.
the format is like the following
03-JUN-52
I use the following script to insert the date
update data."PersonBDates" set BIRTHDATE = to_date('13-SEP-47', 'DD-MON-YY');
and i also used
update data."PersonBDates" set BIRTHDATE = to_date('13-SEP-47', 'DD-MON-RR');
but when i check if find it 2074 not 1947.
How to insert this date into my oracle database?
Generally speaking, RR should work, but - not in all cases. You'll have to fix data first because RR will return different values:
for years from 00 to 49 you'll get this century, 20xx, while
50 to 99 will return previous century, 19xx
Here's an example:
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> select
2 to_date('03-07-52', 'dd-mm-rr') rr1,
3 to_date('03-07-52', 'dd-mm-yy') yy1 ,
4 --
5 to_date('03-07-47', 'dd-mm-rr') rr2,
6 to_date('03-07-47', 'dd-mm-yy') yy2
7 from dual;
RR1 YY1 RR2 YY2
---------- ---------- ---------- ----------
03.07.1952 03.07.2052 03.07.2047 03.07.2047
SQL>
As you can see, both RR and YY format mask for year 47 return 2047.
What to do? Concatenate 19 to all years, e.g.
SQL> with test (col) as
2 (select '03-07-52' from dual union all
3 select '03-07-47' from dual
4 )
5 select col,
6 to_date(substr(col, 1, 6) || '19' || substr(col, -2), 'dd-mm-rrrr') result
7 ---------------- ---------------
8 -- this is "03-07-" "19" the last 2 digits
9 --
10 from test;
COL RESULT
-------- ----------
03-07-52 03.07.1952
03-07-47 03.07.1947
SQL>
[EDIT]
If your current inserting script works OK - which I doubt, regarding error code you mentioned in a comment:
ORA-01858: a non-numeric character was found where a numeric was expected
which means that not all input data have the same, expected & correct format of DD-MON-YY, then a simple way to fix birthdates might be this:
subtract 100 years from all dates whose year is larger than 2000
Here's how:
SQL> create table test (birthdate date);
Table created.
SQL> insert into test
2 select to_date('03-07-52', 'dd-mm-rr') from dual union all
3 select to_date('03-07-47', 'dd-mm-rr') from dual;
2 rows created.
SQL> select * from test;
BIRTHDATE
----------
03.07.1952
03.07.2047
SQL> update test set
2 birthdate = add_months(birthdate, -100 * 12)
3 where extract (year from birthdate) > 2000;
1 row updated.
SQL> select * from test;
BIRTHDATE
----------
03.07.1952
03.07.1947
SQL>
You can modify that, of course, if there's someone who actually was born in 2000 or later.
As of error you got (ORA-01858), well, fixing it depends on how exactly you're entering those values into a table.
if it was a SQL*Loader, invalid values would be rejected and stored into the .bad file and you could fix them and reprocess them later
if it was using an external tables, you could use a where clause and omit invalid rows; for example, use regexp_like
Or, your best option is to make sure that all input values are valid dates. Then any option you choose (I mentioned previously) would work without ORA-xxxxx errors.
Alternate way of concatenating 19 to all years, as Littlefoot suggested.
to_date(regexp_replace('13-SEP-47', '([0-9]+$)', '19\1'), 'DD-MON-YYYY')
I would suggest to implement the solution where 01 is not considered as 1901 but 2001 or something similar (I assume that birthday year is not 1901 for any person in your system).
Case when substr(col, -2) < to_char(sysdate,'YY')
then to_date(col, 'DD-MON-YY')
else to_date(substr(col, 1, 6) || '19' || substr(col, -2), 'dd-mm-rrrr'
End
Cheers!!

How are dates stored in Oracle?

How are dates stored in Oracle? For example I know most systems use Epoch time to determine what time it is. By calculating how many seconds away from January 1st 1970. Does Oracle do this as well?
The reason I am asking this is I noticed if you take two dates in Oracle and subtract them you get a floating point of how many days are between.
Example
(Sysdate - dateColumn)
would return something like this (depending on the time)
3.32453703703703703703703703703703703704
Now is Oracle doing the conversion and spitting that format out, or does Oracle store dates with how many days it is away from a certain time frame? (Like Epoch time)
There are two types 12 and 13
http://oraclesniplets.tumblr.com/post/1179958393/my-oracle-support-oracle-database-69028-1
Type 13
select dump(sysdate) from dual;
Typ=13 Len=8: 220,7,11,26,16,41,9,0
The format of the date datatype is
Byte 1 - Base 256 year modifier : 220
2 - Base 256 year : 256 * 7 = 1792 + 220 = 2012
3 - Month : 11
4 - Day : 26
5 - Hours : 16
6 - Minutes : 41
7 - Seconds : 09
8 - Unused
2012-11-26 16:41:09
Type 12
select dump(begindate) from tab;
Typ=12 Len=7: 100,112,2,7,1,1,1
The format of the date datatype is
byte 1 - century (excess 100) 100 - 100 = 00
byte 2 - year (excess 100) 112 - 100 = 12
byte 3 - month = 2
byte 4 - day = 7
byte 5 - hour (excess 1) 1 - 1 = 0
byte 6 - minute (excess 1) 1 - 1 = 0
byte 7 - seconds (excess 1) 1 - 1 = 0
0012-02-07 00:00:00
From the manual at http://docs.oracle.com/cd/E11882_01/server.112/e26088/sql_elements001.htm#sthref151
For each DATE value, Oracle stores the following information: year, month, day, hour, minute, and second
So apparently it's not storing an epoch value which is also confirmed by this chapter of the manual:
The database stores dates internally as numbers. Dates are stored in fixed-length fields of 7 bytes each, corresponding to century, year, month, day, hour, minute, and second
How are dates stored in Oracle?
The two data types 12 and 13 are for two different purposes.
Type 12 - Dates stored in table
Type 13 - Date returned by internal date functions like SYSDATE/CURRENT_DATE, also when converting a string literal into date using TO_DATE or ANSI Date literal DATE 'YYYY-MM-DD'.
Test cases:
Basic table setup for type 12:
SQL> CREATE TABLE t(col DATE);
Table created.
SQL> INSERT INTO t SELECT SYSDATE FROM dual;
1 row created.
SQL> COMMIT;
Commit complete.
Check the different cases:
SQL> SELECT DUMP(col) FROM t;
DUMP(COL)
--------------------------------------------------------------------------------
Typ=12 Len=7: 120,116,3,17,18,6,55
SQL> SELECT DUMP(SYSDATE) FROM dual;
DUMP(SYSDATE)
--------------------------------------------------------------------------------
Typ=13 Len=8: 224,7,3,17,17,5,54,0
SQL> SELECT DUMP(CURRENT_DATE) FROM dual;
DUMP(CURRENT_DATE)
--------------------------------------------------------------------------------
Typ=13 Len=8: 224,7,3,17,17,14,20,0
SQL> SELECT DUMP(TO_DATE('17-DEC-1980 12:12:12','DD-MON-YYYY HH24:MI:SS')) FROM dual;
DUMP(TO_DATE('17-DEC-198012:12:12','
------------------------------------
Typ=13 Len=8: 188,7,12,17,12,12,12,0
Using ANSI Date literal, just like TO_DATE:
SQL> SELECT DUMP(DATE '2016-03-17') FROM dual;
DUMP(DATE'2016-03-17')
--------------------------------
Typ=13 Len=8: 224,7,3,17,0,0,0,0
SQL> INSERT INTO t SELECT to_date('17-DEC-1980 12:13:14','DD-MON-YYYY HH24:MI:SS') FROM dual;
1 row created.
SQL> COMMIT;
Commit complete.
SQL> SELECT DUMP(col) FROM t;
DUMP(COL)
--------------------------------------------------------------------------------
Typ=12 Len=7: 120,116,3,17,18,6,55
Typ=12 Len=7: 119,180,12,17,13,14,15
SQL>
As you can see, while storing a date in the table, it uses type 12. The second type 13 is used when converting a string literal into date using date functions or when date returned by internal date functions like SYSDATE/CURRENT_DATE.

Resources