Format string does't match - oracle

I have one problem in my query and I don't see where the problem is. So the problem is when I run the query I get error like
ORA-01861: literal does not match format string
01861. 00000 - "literal does not match format string"
*Cause: Literals in the input must be the same length as literals in
the format string (with the exception of leading whitespace). If the
"FX" modifier has been toggled on, the literal must match exactly,
with no extra whitespace.
*Action: Correct the format string to match the literal.
So far my query is here
SELECT rp.*
FROM responsible_persons rp
LEFT JOIN projects p ON p.ProjectID = rp.ProjectID
WHERE rp.UserID = 195
AND (SYSDATE BETWEEN p.StartDate AND p.EndDate)
So far I try to convert StartDate and EndDate to_date() but still I have problem.
What is wrong here ? Where I made mistake ?

You really shouldn't store dates as strings.
Now, having said that, you would want to change your code to
AND (SYSDATE BETWEEN TO_DATE(p.StartDate,'YYYY-MM-DD') AND TO_DATE(p.EndDate,'YYYY-MM-DD'))
But understand that if p.EndDate is '2020-08-28' and SYSDATE is 2020-08-28 07:49:30, then you won't get a match because your date strings don't contain the time component that SYSDATE contains. So you might also want to strip the time component off of SYSDATE with this
TRUNC(SYSDATE)
As suggested by Roberto, you could manipulate the NLS_DATE_FORMAT for your session to get past this problem. But if you have other dates stored as strings and they aren't in the same format, then you've just pushed another problem onto the stack.

Try to set the NLS_DATE_FORMAT in your session to the values in your table, that sysdate can get the same format as the data you have there:
ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD' ;
SELECT rp.*
FROM responsible_persons rp
LEFT JOIN projects p ON p.ProjectID = rp.ProjectID
WHERE rp.UserID = 195
AND (SYSDATE BETWEEN p.StartDate AND p.EndDate)
An example
SQL> create table t ( c1 varchar2(20) , c2 varchar2(20) ) ;
Table created.
SQL> insert into t values ( '22.01.2020 10:00:00' , '22.01.2020 21:00:00' ) ;
1 row created.
SQL> select * from t where ( sysdate between c1 and c2 ) ;
select * from t where ( sysdate between c1 and c2 )
*
ERROR at line 1:
ORA-01843: not a valid month
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss' ;
Session altered.
SQL> select * from t where ( sysdate between c1 and c2 ) ;
no rows selected
SQL>

Related

select record by date is now in oracle

I have following table
Item
Insert_Date
A
11-JAN-23
B
10-JAN-23
And I want to select records have Insert_Date equal Now date without write
select * from *My_Table* where insert_date = '11-JAN-23' ;
I tried
select * from *My_Table* where insert_date = TRUNC(CURRENT_DATE) ;
But it doesn't work;
In Oracle, a DATE is a binary data-type that ALWAYS has the components year, month, day, hour, minute and second. However, client applications (SQL*Plus, SQL Developer, etc.) often do not display the entire DATE and only display the date component and not the time component; that does not mean that the time component does not exist, only that you aren't seeing it with the default formatting.
This means that your date probably also has a non-midnight time component and your query is not matching on the time components. To solve it, you can select on a range:
SELECT *
FROM My_Table
WHERE insert_date >= TRUNC(CURRENT_DATE)
AND insert_date < TRUNC(CURRENT_DATE) + INTERVAL '1' DAY;
Or you can use TRUNC, but that would prevent you using an index on the insert_date column:
SELECT *
FROM My_Table
WHERE TRUNC(insert_date) = TRUNC(CURRENT_DATE);
Note: To change how SQL*Plus and SQL Developer format dates in your current session, you can use:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
Try:
SELECT * FROM My_Table WHERE Insert_Date = CAST( GET_DATE() AS Date)

Implicit conversion of datatypes from varchar2 to date, number etc

Say I have some columns that are currently varchar2 values, in a table Table_A.
Given that they are the correct format for date (formatted through an update statement with to_date), and I want to insert data from Table_A that has the original varchar2 values, into Table_B which has corresponding Date columns - will Oracle do the conversion from varchar2 to Date implicitly, if the date format is correct?
Likewise, I wonder if Oracle would convert a decimal number stored as Varchar2 to a Number(N,M) with the corresponding correct format in the target table.
The reason I am asking, is to see if I can avoid writing large queries that have to first switch column types before doing the select and then insert into target table.
You can do this, it's all about NLS_DATE_FORMAT.
But there is risk:
create table a(
pk integer not null,
dt varchar2(30)
);
create table b(
pk integer not null,
dt date
);
--
-- This example shows date truncation because of the nls_date_format
--
alter session set nls_date_format='DD-MON-YYYY';
insert into b values(1, sysdate);
select to_char(dt, 'YYYY-MM-DD HH24:MI:SS') dt from b;
-- 2021-02-02 11:53:05
insert into a select * from b;
select * from a;
-- 02-FEB-2021
delete b;
insert into b select * from a;
select to_char(dt, 'YYYY-MM-DD HH24:MI:SS') dt from b;
-- 2021-02-02 00:00:00
--
-- This example shows a working conversion
---
alter session set nls_date_format='YYYY-MM-DD HH24:MI:SS';
delete a;
delete b;
insert into b values(1, sysdate);
select to_char(dt, 'YYYY-MM-DD HH24:MI:SS') dt from b;
-- 2021-02-02 11:53:05
insert into a select * from b;
select * from a;
-- 2021-02-02 11:53:05
delete b;
insert into b select * from a;
select to_char(dt, 'YYYY-MM-DD HH24:MI:SS') dt from b;
-- 2021-02-02 11:53:05
--
-- This example shows a failure because of bad date mask.
--
alter session set nls_date_format='YYYY-MM-DD';
delete a;
delete b;
insert into b values(1, sysdate);
select to_char(dt, 'YYYY-MM-DD HH24:MI:SS') dt from b;
-- 2021-02-02 11:53:05
insert into a select * from b;
select * from a;
-- 2021-02-02
alter session set nls_date_format='Dy DD/MM HH24:MI:SS';
delete b;
insert into b select * from a;
-- ORA-01846: not a valid day of the week
In short, don't do it unless absolutely necessary.
If you have to do it, make sure you control nls_date_mask by setting it in your script prior to the SQL execution.
The answer is easier for numbers - as long as the decimal separator is consistent across all tables and columns. If a column in one table has the format 33.29 and a column in another table has the format 33,29 for the same thing - because it uses comma as the decimal separator - you will have problems.
For dates it will be a bit more complicated - especially if some dates are like '12/31/2020' and others are like '12/31/2020 00:00:00'.
If all numbers are in the exact same format, and if all dates are in the exact same format, it should work; for dates, you will need to make sure that nls_date_format is the same format as your strings (or change it with alter session), and for numbers you must make sure that nls_numeric_characters shows the same decimal separator (and, if used, the same grouping separator) as your numeric strings.
I might do what you are suggesting for "play" databases (for testing, for example) - or in an environment where you can't do too much damage. I wouldn't do this in production, if non-trivial things depend on the database and the data in it.

DECODE function in ORACLE does not give date 01-01-1900 as output

In oracle in our project where DECODE function is the recommended guideline to use them, there are issues when converting the date 01-01-1900.
Consider the below decode
CAST(DECODE(COL1,'A',DATECOL,TO_DATE('01011900','DDMMYYYY')) AS DATE) - (The CAST is also a mandatory guideline)
If,
COL1 DATECOL
A 2019-04-05
B 2018-01-01
C 2020-05-01
I get the resulting data as
COL1 OUTPUT
A 2019-04-05
B 2000-01-01
C 2000-01-01
The DECODE function gives me 2000-01-01 instead of 1900-01-01.
I have checked out the NLS parameters and dabbles around by modifying different things in TO_DATE function. Nothing worked out.
Is it possible that your DATECOL in the database is actually a string? Because if that is the case, then DECODE always takes the first potential return item to set the datatype. And once you start mixing and matching datatypes, bad things can be happen.
For example
SQL> alter session set nls_date_format = 'YY-MM-DD';
Session altered.
SQL> with t as
2 ( select 'A' col1, '2010-01-01' datecol from dual union all
3 select 'B' col1, '2010-01-01' datecol from dual )
4 select CAST(DECODE(COL1,'A',DATECOL,TO_DATE('01011900','DDMMYYYY')) AS DATE)
5 from t;
CAST(DEC
--------
10-01-01
00-01-01
That seems to look OK, but if I dig into the value that actually came back after all the jumping through datatypes
SQL> with t as
2 ( select 'A' col1, '2010-01-01' datecol from dual union all
3 select 'B' col1, '2010-01-01' datecol from dual )
4 select to_char(CAST(DECODE(COL1,'A',DATECOL,TO_DATE('01011900','DDMMYYYY')) AS DATE),'dd-mm-yyyy')
5 from t;
TO_CHAR(CA
----------
01-01-2010
01-01-2000
you can see that the lack of a full century specification has "mangled" the result. In particular, the tools you are using (SQL Developer and others) will have their own formatting of results which can mask what might be happening with datatypes.

Oracle - Inline View - External WHERE condition applied inline

We have a table where dates are stored as VARCHAR2(It's legacy data table which we have no control on!) in format of YYYYMMDD. We have only SELECT privilege on table (Not feasible to write procedure/functions).
Need to select all rows from table where date is > sysdate.
We apply regular expression check for valid format and additional checks to ensure that day is valid for given month. All this works great! Our inline view selection ensures that only records with valid date strings are picked.
But, when we apply condition to check > sysdate as an external clause - we get invalid date for given month error even though inline view selection ensures that no such records are picked.
It looks like query execution is applying the condition from outer clause before inline view conditions are applied. Appreciate any comments on the behavior; and, how can we ensure that conditions from outside are applied only once inline conditions are met?
Data and Used Queries:
CREATE TABLE TEST_DATA_TABLE
(
DATESTRING VARCHAR2(20 BYTE)
);
Insert 3 rows with values:
19960322 --Valid Date in past
19831131 --Invalid Date 11/31
20180224 --Valid Date > SYSDATE
Valid data selection:
(Where clause 1 ensures format and clause 2 ensures valid date for month):
SELECT datestring AS i_dob
FROM test_data_table
WHERE REGEXP_LIKE (TRIM (datestring),
'(19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])')
AND TRIM (datestring) <=
TO_CHAR (
LAST_DAY (
TO_DATE (SUBSTR (TRIM (datestring), 1, 6) || '01',
'YYYYMMDD')),
'YYYYMMDD')
Above query works fine and return valid rows with valid date string,
To select records having date string > SYSDATE, above data is used inline and we apply condition >SYSDATE as below.
SELECT i_dob
FROM (
SELECT datestring AS i_dob
FROM test_data_table
WHERE REGEXP_LIKE (TRIM (datestring),
'(19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])')
AND TRIM (datestring) <=
TO_CHAR (
LAST_DAY (
TO_DATE (SUBSTR (TRIM (datestring), 1, 6) || '01',
'YYYYMMDD')),
'YYYYMMDD')
) X
WHERE TO_DATE (X.I_DOB, 'YYYYMMDD') > SYSDATE
It starts throwing error: ORA-01839: date not valid for month specified
Looks like the conditions are applied before all inline view conditions are checked.
You can get around this by making the inline view be actioned before the outer query by adding an additional rownum column to it (the presence of the rownum column means that Oracle needs to calculate that column for the subquery it applies to before it can further filter on it.
So, your query would become:
SELECT i_dob
FROM (
SELECT datestring AS i_dob,
rownum rn
FROM test_data_table
WHERE REGEXP_LIKE (TRIM (datestring),
'(19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])')
AND TRIM (datestring) <=
TO_CHAR (
LAST_DAY (
TO_DATE (SUBSTR (TRIM (datestring), 1, 6) || '01',
'YYYYMMDD')),
'YYYYMMDD')
) X
WHERE TO_DATE (X.I_DOB, 'YYYYMMDD') > SYSDATE;
I would add a comment into your query explaining the presence of this column, otherwise some developer in the future may think "eh? This does nothing; I'll remove it!".
(Also of note is in 12.2, they have added/amended functions to allow for easier data validation, which would simplify your query when you get to 12.2!)

how to get date part in oracle

id name date
1 AAA 12-01-15
2 BBB 19-09-12
3 CCC 23-07-10
4 DDD 06-10-01
5 EEE 08-11-05
6 FFF 18-04-99
7 GGG 07-08-12
i have tried it but by converting it is possible but i dont want to convert it i want to extract only date part help me out please
i have a table with date field with datatype i want to extract date from date field
my condition is i want to get records which equal to sysdate i.e i want to get records which are inserted on present day which equal to datepart
If I understand correctly the 'date' column in your table has the DATE datatype. If so then the following should get what you're looking for:
SELECT t.*
FROM YOUR_TABLE t
WHERE TRUNC(t.DATE_FIELD) = TRUNC(SYSDATE)
Of course, based on the data in your question the above query will not return any rows, but if there was data in the table with the same date as SYSDATE they would be returned.
(And by-the-way - since DATE is a data type it's a Bad Idea to use it as the name of a column. Here I've changed it to DATE_FIELD).
Best of luck.
If your column is varchar, then use this
select * from (
select '21-10-15' as dt from dual)
where to_date(dt,'dd-mm-yy') = trunc(sysdate)
If your column is on type date and you are storing only date, not timestamp, then use this.
select * From (
select to_date('21-10-15','dd-mm-yy') as dt from dual)
where dt = trunc(sysdate)
If you are saving the column as date along with time, then use Bob's solution
select * From (
select to_date('21-10-15','dd-mm-yy') as dt from dual)
where trunc(dt) = trunc(sysdate)
I changed the column to dt. Change it as per your convenience.

Resources