What is the best data type for the field of format "YYYY-MM-DD" in oracle 11g? - oracle

I'm creating tables in Oracle 11g table and came across one date field of format "YYYY-MM-DD".
I don't want to use varchar2 for this and when I use number(5), it's still accepting the input. Then what's the meaning of limit 5 here?
Please suggest me the best datatype I can use here.

This is, obviously, a date format mask. If you're about to store dates into that column, you should use the DATE datatype, such as
SQL> create table test
2 (datum date);
Table created.
Don't use VARCHAR2 (put strings into it, not dates) nor NUMBER (put numbers into it, not dates) datatypes for that. You'll regret it sooner than you think.
I'm going to enter some values into the table, showing different ways of how you could do that - it is important that you insert dates, not strings into it. Never rely on Oracle, implicitly converting strings you might provide to dates. Sooner or later, it'll produce an error.
SQL> insert into test values (date '2018-12-25');
1 row created.
SQL> insert into test values (to_date('09.05.2018', 'dd.mm.yyyy'));
1 row created.
SQL> insert into test values (sysdate);
1 row created.
Now, several ways of selecting that value:
This one returns date in a format currently set by my database's NLS settings:
SQL> select * from test;
DATUM
--------
25.12.18
09.05.18
09.05.18
I'm forcing it to return values in desired format, using ALTER SESSION:
SQL> alter session set nls_date_format = 'yyyy-mm-dd';
Session altered.
SQL> select * from test;
DATUM
----------
2018-12-25
2018-05-09
2018-05-09
Yet another format; note that value inserted via the SYSDATE function (which returns DATE) contains date and time component. It was "invisible" in previous examples:
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> select * from test;
DATUM
-------------------
25.12.2018 00:00:00
09.05.2018 00:00:00
09.05.2018 08:03:50
Using TO_CHAR function with some format (such as dd-mon-yyyy). I'm also requesting Oracle to "translate" month name into English (as my database works in Croatian):
SQL> select to_char(datum, 'dd-mon-yyyy', 'nls_date_language = english') datum from test;
DATUM
-----------
25-dec-2018
09-may-2018
09-may-2018
SQL>
[EDIT]
Oracle doesn't store DATE values in any "human" readable format (there's more to read on the Internet, Google for it). It is a format mask that represents that value to you.
I strongly suggest you NOT to store dates into any datatype column but DATE. It's a time bomb, waiting to explode (and then it'll hurt). Nobody stops you from entering a value as '1234-99-66' or '12-345-678'; what will you do with it, then?
Consider creating a view on a top of the table which uses TO_CHAR function and returns the value in a format you want ('yyyy-mm-dd'). DATE datatype column in a table makes sure that values are valid, and the view will let the third-party application to accept values it finds appropriate.
For example:
SQL> create view v_test as
2 select to_char(datum, 'yyyy-mm-dd') datum
3 from test;
View created.
SQL> select * from v_test;
DATUM
----------
2018-12-25
2018-05-09
2018-05-09
SQL>
So: you wouldn't let the third-party application to access the table, but the view instead.

Related

How to update year only in date format dd-MON-yyyy use Oracle sql plus

DOB data type : DATE
13-JAN-76
10-FEB-80
17-MAR-79
---------------
Expected output
13-JAN-04
10-FEB-04
17-MAR-04
I tried use this but failed.
update table set dob=to_date(dob,'dd-MON-yyyy')||','||'2004','dd-MON-yyyy') where id='1001';
date format not recognized.
anyone help is much appreciated.
Here's one option:
(just to know date format; you don't have to do that)
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
Here it goes:
SQL> select * from test;
DOB
----------
13.01.1976
10.02.1980
17.03.1979
SQL> update test set
2 dob = add_months(dob, (2004 - extract(year from dob)) * 12);
3 rows updated.
SQL> select * from test;
DOB
----------
13.01.2004
10.02.2004
17.03.2004
SQL>
You update statement relies on the session default date format. Typically this is defined by session parameter NLS_DATE_FORMAT
Better specify it explicitly:
update table set dob = to_date(2004 || TO_CHAR('dob', '-MM-DD'), 'YYYY-MM-DD')

Default milliseconds to 0 in Oracle

I have a timestamp column in Oracle that has format 'MM/DD/YYYY HH24:MI.SxFF6'.
The data looks like below:
11/09/1917 10:45:28.230000
10/19/2014 18:09:28.410000
12/19/2011 11:06:28.340000
I need the timestamp to retain the value except for getting the milliseconds which need to be defaulted to 000000.
I tried query -
cast(to_char(Local_time, 'MM/DD/YYYY HH24:MI:SS') as timestamp(6))
But it is throwing error - "Not valid month"
Does anyone have any ideas on what I can try to get milliseconds to 0. I use Toad to query the table.
Your TIMESTAMP value does not have any format. All you have is a default display format - defined by current user NLS_TIMESTAMP_FORMAT setting.
Try this one:
CAST(Local_time AS TIMESTAMP(0))
If you like to trunc the milliseconds but haven them still available use
CAST(CAST(Local_time AS TIMESTAMP(0)) AS TIMESTAMP(6))
Something like this, perhaps?
SQL> create table test (col timestamp, result timestamp);
Table created.
SQL> insert into test (col) values (to_timestamp('11/09/1917 15:45:28.230000', 'MM/DD/YYYY HH24:MI:SS.FF6'));
1 row created.
SQL> update test set result = cast(col as date);
1 row updated.
SQL> select * From test;
COL RESULT
------------------------- -------------------------
09.11.17 15:45:28,230000 09.11.17 15:45:28,000000
SQL>

different date format to one date format in table

I have two DATE column in table oracle database(12c).sysdate format is:
SQL> select sysdate from dual;
SYSDATE
---------
25-NOV-17
SQ>desc test_table
id NUMBER(10)
LAST_CREATED_DATE DATE
IS_CREATED_DATE DATE
where LAST_CREATED_DATE has different format to IS_CREATED_DATE(sysdate).
because LAST_CREATED_DATE is fixed and i'm reading from file(date format:20100330) where as IS_CREATED_DATE am inserting as sysdate(current date).
insert into test_table (id,LAST_CREATED_DATE,IS_CREATED_DATE) values (123,20100930,sysdate);
but with this insert statement am facing errors.
I tried ALTER SESSION SET NLS_DATE_FORMAT = 'yyyymmdd';.This works fine in current session,but looking for by which i can change ORACLE database date format to yyyymmdd(linux).
You should change your statement like this:
insert into test_table (id,LAST_CREATED_DATE,IS_CREATED_DATE)
values (123,to_date('20100930','yyyymmdd'),sysdate);
There are three ways to accomplish this task :
1)
SQL>conn myschema/mypwd
SQL>insert into test_table values(123,to_date('20100930','yyyymmdd'),sysdate);
2) as you mentioned
SQL>alter session set nls_date_format = 'yyyymmdd';
SQL>insert into test_table values(123,'20100930',sysdate); -- notice that 20100930 is quoted
3) globally(along with the db, needs restart, maybe dangerous on a production system in coordination with existing applications' date format model)
SQL>conn / as sysdba
SQL>alter system set nls_date_format = 'yyyymmdd' scope=spfile;
SQL>shutdown immediate;
SQL>startup;
SQL>conn myschema/mypwd
SQL>insert into test_table values(123,'20100930',sysdate); -- from now on, you don't need to alter your date parameter for every session

Trigger to update week of the year

I want to write a trigger so that when decom_date is inserted or updated the week of the year is updated to the corresponding value.
This is what I have so far, but after inserting a date the week is still null.
create or replace trigger test_trigger
before insert on check_decom
for each row
begin
if inserting then
update check_decom set decom_week= (select to_char(to_date(decom_date,'DD-
MON-YY'),'WW') as week from check_decom) ;
end if;
end;
/
SQL> select * from check_decom;
DECOM_DATE DECOM_WEEK
------------------------------ ----------
23-JUN-17
What am I doing wrong?
Example for Week of a year
SQL> select to_char(to_date(sysdate,'DD-MON-YY'),'WW') as week from dual;
WE
--
28
You're doing a couple of things wrong, starting with date handling. Your decom_date column should be defined as a DATE column - it looks like it might be a string in your sample output. But your handling with sysdate is also wrong, as you're implicitly converting to a string in order to convert it back to a date, which is both pointless and prone to error as this might happen in a session which has different NLS settings. If your column is actually a DATE then you should not be calling to_date() against that either; and if it is a string then that conversion is valid but it should be a DATE.
Then your trigger is querying and trying to update the table that the trigger is against. With no data that doesn't error but doesn't do anything as there is no existing row to update - the one you are inserting doesn't exist yet. If there was data you would get a mutating table error, if you didn't get a too-many-rows exception from the select part.
Row-level triggers can access NEW and OLD pseudorecords to see and manipulate the affected row; you don't need to (and generally can't) use DML queries to access the data in the row you're manipulating.
If your table was defined with a date column and a number column:
create table check_decom(decom_date date, decom_week number);
then your trigger might look something like:
create or replace trigger test_trigger
before insert on check_decom
for each row
begin
if inserting then
:new.decom_week := to_number(to_char(:new.decom_date, 'WW'));
end if;
end;
/
although the if inserting check is a bit pointless as the trigger will only fire on insert anyway. Which in itself might be an issue; you perhaps want it to be set on update as well, but the logic the same, so would be:
create or replace trigger test_trigger
before insert or update on check_decom
for each row
begin
:new.decom_week := to_number(to_char(:new.decom_date, 'WW'));
end;
/
which does what you want:
insert into check_decom (decom_date) values (date '2017-06-23');
1 row inserted.
select * from check_decom;
DECOM_DAT DECOM_WEEK
--------- ----------
23-JUN-17 25
But I wouldn't do this with a trigger at all. From Oracle 11g you can use a virtual column instead:
create table check_decom (
decom_date date,
decom_week generated always as (to_number(to_char(decom_date, 'WW')))
);
Table CHECK_DECOM created.
insert into check_decom (decom_date) values (date '2017-06-23');
1 row inserted.
select * from check_decom;
DECOM_DAT DECOM_WEEK
--------- ----------
23-JUN-17 25

Trying to export a Oracle via PL/SQL gives a date of 0000-00-00

I have inherited an Oracle .dmp file which I'm trying to get into CSV so that I can load it into MySQL.
The general approach I'm using is described here. I'm having a problem with one row though. It contains a date of 5544-09-14 like so:
alter session set nls_date_format = 'dd-MON-yyyy';
select OID, REF, TRADING_DATE From LOAN WHERE REF = 'XXXX';
OID REF TRADING_DATE
--- -------------------- ------------
1523 XXXX 14-SEP-5544
This is garbage data from the legacy system which didn't validate the input dates. I'm wondering why my PL/SQL function to export the data chokes on this value though?
It exports that row with a TRADING_DATE value of '0000-00-00T00:00:00' and I'm not sure why?
SELECT dump(TRADING_DATE) FROM LOAN WHERE REF = 'XXXX';
DUMP(TRADING_DATE)
--------------------------------------------------------------------------------
Typ=12 Len=7: 44,156,9,14,1,1,1
and
SELECT to_char(trading_date, 'YYYYMMDDHH24MISS') FROM LOAN WHERE REF = 'XXXX';
TO_CHAR(TRADIN
--------------
00000000000000
The value stored in that column is not a valid date. The first byte of the dump should be the century, which according to Oracle support note 69028.1 is stored in 'excess-100' notation, which means it should have a value of 100 + the actual century; so 1900 would be 119, 2000 would be 120, and 5500 would be 155. So 44 would represent -5600; the date you have stored appears to actually represent 5544-09-14 BC. As Oracle only supports dates with years between -4713 and +9999, this isn't recognised.
You can recreate this fairly easily; the trickiest bit is getting the invalid date into the database in the first place:
create table t42(dt date);
Table created.
declare
d date;
begin
dbms_stats.convert_raw_value('2c9c090e010101', d);
insert into t42 (dt) values (d);
end;
/
PL/SQL procedure successfully completed.
select dump(dt), dump(dt, 1016) from t42;
DUMP(DT)
--------------------------------------------------------------------------------
DUMP(DT,1016)
--------------------------------------------------------------------------------
Typ=12 Len=7: 45,56,9,14,1,1,1
Typ=12 Len=7: 2d,38,9,e,1,1,1
So this has a single row with the same data you do. Using alter session I can see what looks like a valid date:
alter session set nls_date_format = 'DD-Mon-YYYY';
select dt from t42;
DT
-----------
14-Sep-5544
alter session set nls_date_format = 'YYYYMMDDHH24MISS';
select dt from t42;
DT
--------------
55440914000000
But if I use an explicit date mask it just gets zeros:
select to_char(dt, 'DD-Mon-YYYY'), to_char(dt, 'YYYYMMDDHH24MISS') from t42;
TO_CHAR(DT,'DD-MON-Y TO_CHAR(DT,'YY
-------------------- --------------
00-000-0000 00000000000000
And if I run your procedure:
exec dump_table_to_csv('T42');
The resultant CSV has:
"DT"
"0000-00-00T00:00:00"
I think the difference is that those that attempt to show the date are sticking with internal date data type 12, while those that show zeros are using external data type 13, as mentioned in note 69028.1.
So in short, your procedure isn't doing anything wrong, the date it's trying to export is invalid internally. Unless you know what date it was supposed to be, which seems unlikely given your starting point, I don't think there's much you can do about it other than guess or ignore it. Unless, perhaps, you know how the data was inserted and can work out how it got corrupted.
I think it's more likely to be from an OCI program than what I did here; this 'raw' trick was originally from here. You might also want to look at note 331831.1. And this previous question is somewhat related.

Resources