SQL query for date format for CLOB field is not working - sql

Hi I am using the below query to get the date in the format 'DD-MM-YYYY' from a CLOB field from ORACLE Toad.
Select ID, NVL(TO_CHAR(xmltype(XML_RAW).extract('//ROWSET//ROW//MJR_V//MJR_V_ROW//EARLIEST_ACCEPT_DATE/text()').getStringVal(), 'DD-MM-YYYY'),'')
AS Dateformat from table1 where ID = 102
It thorws error:
ORA:01722: Invalid number
But if I use the above query direct DB columns (NOT CLOB FIELDS) then it executes fine.
Select ID, NVL(TO_CHAR(Start_Date, 'DD-MM-YYYY'),'')
AS Dateformat from table1 where ID = 102
Please let me the solution.

You shouldn't run to_char on varchar2
to_char function gets a date (or a number) as an argument and converts it to a varchar2.
If you use it on a varchar2, then oracle implicitly converts the string to a date according to NLS_DATE_FORMAT
So you sould probably do something like this:

Related

ORA-01481: invalid number format model in oracle insert query

I have below query where i am getting error as
ORA-01481: invalid number format model
The user is attempting to either convert a number to a string via TO_CHAR or a string
to a number via TO_NUMBER and has supplied an invalid number format model parameter.
I am using this query in stored procedure. The day_id column is number data type and the value stored in this column as YYYYMMDD. The month_id column is also number data type and i want to stored the value in this column as YYYYMM
INSERT INTO TEST_CHECK(MONTH_ID) VALUES
(to_char(REC.day_id, 'YYYYMM'));
You're applying a conversion to a number as if it was a date, trying to use the result (a string) as a number.
SQL> create table TEST_CHECK(MONTH_ID number);
Table created.
SQL> INSERT INTO TEST_CHECK(MONTH_ID) VALUES(to_char(20180101, 'YYYYMM'));
INSERT INTO TEST_CHECK(MONTH_ID) VALUES(to_char(20180101, 'YYYYMM'))
*
ERROR at line 1:
ORA-01481: invalid number format model
You may need something like:
SQL> INSERT INTO TEST_CHECK(MONTH_ID) VALUES(substr(to_char(20180101), 1, 6));
1 row created.
I would remember that storing dates and months in such a way is not a good idea.
Use
INSERT INTO TEST_CHECK(MONTH_ID) VALUES
(substr(REC.day_id, 1, 6));
instead, since both day_id and month_id are numbers.
If day_id were in date format you could make such a conversion to char but this not the case.
You may apply to_char conversion for REC.day_id as to_char(REC.day_id) but if there's no non-numeric character, oracle considers number as char implicitly without to_char, during a string operation such as substr.

Use format pattern from regexp_replace in to_char

I have a SQL stored in a column where the format for date is in square brackets:
sql_column
------------------------------------------------------------------------------
select col1 from table1 where col2 = to_date('[DD-MON-YYYY]', 'DD-MON-YYYY');
select col1 from table2 where col2 between [YYYYMMDD]00000 and [YYYYMMDD]99999 and col3 = to_date('[DD-MON-YYYY]', 'DD-MON-YYYY');
....
I don't know which format can be there beforehand, but it is always a date format.
Is there a way to use regexp_replace (or regexp_substr or even with regexp_* functions) to find and replace the pattern with the result of to_char of my given date and pattern taken from the db column.
Perhaps something like this (which doesn't work obviously):
select sql_column,
regexp_replace(sql_column, '\[(.+?)\]', to_char(some_date, '\1'))
from my_table;
Could you please help?
There is no way to parse ALL the possible date formats. For example, if you see '01/11/2017' in a varchar field you cannot say if it refers to November 1st or January 11th.
Said that, you can use a common table expression to choose the best pattern and then use it to convert the string value to date. For example:
select * from
(select
case
when REGEXP_LIKE(col2, '^[0-9]{2}/[0-9]{2}/[0-9]{4}$') then 'DD/MM/YYYY'
when REGEXP_LIKE(col2, '^[0-9]{14}$') then 'YYYYMMDDHH24MISS'
end pattern, table1.*
from table1) x
where to_date(x.col2, x.pattern) = to_date('01/11/2017','DD/MM/YYYY')
This approach would probably lead to a full table scan so it is far from being efficient. If the original table is large, I advice creating a materialized view with the converted date to improve performance.
You'll need a bit of dynamic SQL to solve this problem.
I do not present a complete solution, but this should give you a hint how to approach it.
Let's approach it bottom up.
What you actually need is a REPLACE statement, that transforms you SQL text in the required form with the paramater date.
This could be for your example this statement for teh first example (parameter date is 30.11.2017)
select replace(sql_column, '[DD-MON-YYYY]','30-NOV-2017') from my_table;
If you run the first statement on your first row you get the expected result:
select col1 from table1 where col2 = to_date('30-NOV-2017', 'DD-MON-YYYY');
So how to get those REPLACE statements. One possibility is to write a PL/SQL function.
The function has two parameters - the original SQL string and teh parameter date.
Using regexp you scrap the date format mask.
With dynamic SQL (EXECUTE IMMEDIATE) you format you parameter DATE as string with propper format.
Finally the REPLACE statement is returned.
create or replace function format_date(i_txt IN VARCHAR2, i_date DATE) return VARCHAR2 is
v_date_format VARCHAR2(4000);
v_form_date VARCHAR2(4000);
v_param VARCHAR2(4000);
v_form VARCHAR2(4000);
v_sql VARCHAR2(4000);
BEGIN
v_param := regexp_substr(i_txt, '\[(.+?)\]');
v_date_format := replace(replace(v_param,'[',null),']',null);
v_sql := 'select to_char(:d,'''||v_date_format||''') as my_dt from dual';
execute immediate v_sql into v_form_date using i_date;
v_form := 'select replace(sql_column, '''||v_param||''','''||v_form_date||''') from my_table';
return (v_form);
END;
/
NOTE that I handle only the first date mask in the string, you'll need to loop on all occcureces to get correct the second example!

SQL - literal does not match format string in INSERT INTO

I've created an empty table--in my website that holds a bunch of tables-- that has the following columns/data types:
NAME -- VARCHAR2
MRN -- NUMBER
DATE_S -- DATE
E -- DATE
DELI -- DATE
WB -- VARCHAR2
ST_ID -- VARCHAR2
COMMENTS --VARCHAR2
EI -- NUMBER
Below is one of almost 800 rows of code I am using to populate the table.
INSERT INTO SANDBOX.W_C VALUES ('S,E',11300033,'2012-02-18 00:00:00','2012-03-01 00:00:00','2013-02-18 00:00:00','N','006i',NULL,NULL);
When I run that piece of code I get the following message: literal does not match format string. What am I doing wrong?
You need to_Date
INSERT INTO SANDBOX.W_C VALUES ('S,E',11300033,
TO_DATE('2012-02-18', 'yyyy-mm-dd'),
TO_DATE('2012-03-01', 'yyyy-mm-dd'),
TO_DATE('2013-02-18', 'yyyy-mm-dd'),'N','006i',NULL,NULL);
When you provide a date as a string, the database uses it's default settings to try to convert the string. The best way to handle this is the use of to_date, as in scaisEdge's answer.
However, you can also change the default date mask using alter session before you run the insert statements:
ALTER SESSION SET NLS_DATE_FORMAT='yyyy-mm-dd hh24:mi:ss';

Wrong date format for input parameter?

CREATE OR REPLACE PROCEDURE PROC1(
V_STARTTIME IN DATE,
V_ENDTIME IN DATE)
BEGIN
INSERT INTO TAB1
SELECT COINS FROM TAB2
WHERE DATE BETWEEN TO_DATE(V_STARTTIME,'MM/DD/YYYY') AND TO_DATE(V_ENDTIME,'MM/DD/YYYY');
COMMIT;
END;
SAMPLE DATE in Tab2 IS TIMESTAMP DATATYPE 5/5/2014 9:46:38.000000 AM
When I try to execute
Execute PROC1(TO_DATE('5/5/2014','MM/DD/YYYY'),TO_DATE('5/6/2014','MM/DD/YYYY'));
the procedure is successfully completed but my Insert into was ignored.
I tried printing the input date through dbms_output.put_line and the date did not return.
This is very, very similar to the question you asked yesterday.
If v_starttime and v_endtime are of type date, it makes no sense to call to_date on them. to_date does not take an argument of type date. It takes a parameter of type varchar2. If you try to pass a date to to_date, Oracle has to implicitly cast the date to a varchar2 using the session's NLS_DATE_FORMAT. If that doesn't match the format mask you're passing to to_date, you may get an error or you may get an incorrect result. As in yesterday's question, you want to avoid implicit conversions.
A date in Oracle has both a day and a time component (to the second). If you are doing the to_date in order to ensure that the time component is midnight, use the trunc function instead.
INSERT INTO TAB1( column_name )
SELECT COINS
FROM TAB2
WHERE <<timestamp column>> BETWEEN trunc( v_starttime ) AND trunc( v_endtime );
You say that your "insert was ignored". That seems highly unlikely. It's much more likely that your SELECT statement returned 0 rows so your INSERT inserted 0 rows. That's not an error. If you want to treat it as an error, you'd need to check SQL%ROWCOUNT after the INSERT and throw an error if the INSERT statement inserts 0 rows.
If the SELECT was not selecting any rows because of an implicit conversion error, then getting rid of the to_date and potentially adding the trunc would fix the problem.
The function TO_DATE requires string as first parameter.
CREATE OR REPLACE PROCEDURE PROC1(
V_STARTTIME IN DATE,
V_ENDTIME IN DATE)
BEGIN
INSERT INTO TAB1
SELECT COINS FROM TAB2 WHERE DATE BETWEEN V_STARTTIME AND V_ENDTIME;
COMMIT; --You should not use commit in procedure.
END;

Oracle vs. Hypersonic SQL

I need to select by date in a SQL query, for example
SELECT * FROM foo WHERE date = '2009-09-09'
That query works in my Hypersonic test database, but not Oracle, which seems to requires:
SELECT * FROM foo WHERE date = TO_DATE('2009-09-09', 'yyyy-mm-dd')
Is there a way to select by date uniformly across these two databases?
I found the answer - you can create the TO_DATE function in HyperSonic and then the second query works in both. For example, make the class:
public class Date {
public static String toDate( String value, String format ) {
return value;
}
}
And the query
SELECT * FROM foo WHERE date = TO_DATE('2009-09-09', 'yyyy-mm-dd')
works in both.
You could try H2 database as your in memory database (http://www.h2database.com). It should have decent Oracle compablity mode.
HSQLDB 2.0 supports ANSI date literals just as Oracle. So if you can upgrade to HSQLDB 2.0, you can use:
SELECT *
FROM foo
WHERE date_column = DATE '2009-09-09'
in both database (actually a lot more databases even)
A "date = 'literal string'" predicate in Oracle is usually not recommended - it is sensitive to NLS_DATE_FORMAT settings and often leads to misunderstanding on what you're looking for in a result set (in your example above do you want all records for the day or just those created exactly at midnight?)
If you need a uniform query string for both databases, you might rename the table in Oracle and create a view with the name foo and cast the date datatype to varchar2 in the view logic. You'll probably need to add a function-based index to the table to allow efficient searching on the recast value.
If you can, you can set your NLS_DATE_FORMAT in Oracle session, that way you do not need to use the TO_DATE function, oracle will do this for you behind the scenes.
SQL> select value from v$nls_parameters where parameter = 'NLS_DATE_FORMAT';
VALUE
----------------------------------------------------------------
DD/MM/YYYY
SQL> create table nls_date_test ( id number(10) , date_entered date );
Table created.
SQL> insert into nls_date_test values ( 1 , '31/05/2009' );
1 row created.
SQL> insert into nls_date_test values ( 2 , '30/05/2009' );
1 row created.
SQL> select * from nls_date_test where date_entered = '2009-09-09';
select * from nls_date_test where date_entered = '2009-09-09'
*
ERROR at line 1:
ORA-01861: literal does not match format string
SQL> alter session set nls_date_format = 'YYYY-MM-DD';
Session altered.
SQL> select * from nls_date_test where date_entered = '2009-05-30';
ID DATE_ENTER
---------- ----------
2 2009-05-30
SQL> select value from v$nls_parameters where parameter = 'NLS_DATE_FORMAT';
VALUE
----------------------------------------------------------------
YYYY-MM-DD
SQL>