Help with "ORA-00907: missing right parenthesis" error please - sql

I am getting a ORA-00907: missing right parenthesis from the following code below
dbQuery:= TQuery.Create(nil);
dbQuery.DatabaseName:= dbMain.DatabaseName;
with dbQuery do
begin
SQL.Add('select payee_address_zip, EXTRACT(WEEKDAY FROM check_date) as DOW, ');
SQL.Add('(cmcl_bank_cleared - check_date) as DateDiff from AP_Master ');
SQL.Add('where (cmcl_bank_cleared is not null) AND ((cmcl_bank_cleared - check_date) >=:DaysParam)');
SQL.Add('order by payee_address_zip, DOW, DateDiff');
try
ParamByName('DaysParam').AsInteger:= days_param_int;
Open;
//do something else here
except on E:EDatabaseError do
begin
raise ECustomException.create('Error opening query for step 1 of computing Float Factors!');
end;//except
end; //try
end; //with
dbQuery.Free;
Can someone tell me what is going on? I can't seem to see that i have left out a parenthesis, and this SQL works just fine against a Interbase test database. However, when moving it to a clients oracle database, it crashes, with the error above.

Let's check with SQL*Plus, so you can see exactly at which place the parser expects a right parenthesis:
SQL> create table ap_master(payee_address_zip,check_date,cmcl_bank_cleared)
2 as
3 select 1,sysdate,sysdate+1 from dual
4 /
Table created.
SQL> var DaysParam number
SQL> exec :DaysParam := 1
PL/SQL procedure successfully completed.
SQL> select payee_address_zip
2 , EXTRACT(WEEKDAY FROM check_date) as DOW
3 , (cmcl_bank_cleared - check_date) as DateDiff
4 from AP_Master
5 where (cmcl_bank_cleared is not null)
6 AND ((cmcl_bank_cleared - check_date) >=:DaysParam)order by payee_address_zip, DOW, DateDiff
7 /
, EXTRACT(WEEKDAY FROM check_date) as DOW
*
ERROR at line 2:
ORA-00907: missing right parenthesis
So there is something with your EXTRACT function. This is the relevant piece of documentation about the EXTRACT (datetime) function:
http://download.oracle.com/docs/cd/E11882_01/server.112/e17118/functions059.htm#sthref1117
It doesn't mention your WEEKDAY keyword. You can get the weekday by using the TO_CHAR function though. I don't know which date format element you want exactly. I guess 'D' or 'DAY'. You can look them up here:
http://download.oracle.com/docs/cd/E11882_01/server.112/e17118/sql_elements004.htm#CDEHIFJA
If you change the EXTRACT expression and replace it with a TO_CHAR, it will work:
SQL> select payee_address_zip
2 , to_char(check_date,'d') as DOW
3 , (cmcl_bank_cleared - check_date) as DateDiff
4 from AP_Master
5 where (cmcl_bank_cleared is not null)
6 AND ((cmcl_bank_cleared - check_date) >=:DaysParam)order by payee_address_zip, DOW, DateDiff
7 /
PAYEE_ADDRESS_ZIP D DATEDIFF
----------------- - ----------
1 4 1
1 row selected.
Regards,
Rob.

It looks like you're missing a space on the end of this line:
SQL.Add('where (cmcl_bank_cleared is not null) AND ((cmcl_bank_cleared - check_date) >=:DaysParam)');

Related

how to handle invalid date in Oracle SQL

There is a column that displays some statements for transactions
Ex: 'date-05-03-2020-Tran-100002345-W.44321-CR-9999eu843'
And I fetched out only the date from the statement. In some cases, there is an invalid date such as date-05-032-2020 (three numbers in month instead of two numbers)
So when I executed the query I got an error as I am using TO_DATE function to convert the varchar to date after extracting it from the previous statement
So what I need is a function like IfError in excel sheet but in oracle SQL
Ex: if the DATE_x is invalid then replace it with DATE_x2
with x as(
select TO_DATE('01/20/2021','DD-MM-YYYY') DATE_x,
TO_DATE('01/02/2021','DD-MM-YYYY') DATE_x2
from dual
)
select
DATE_x2
from x;
Please advise
There is a default... on conversion error parameter in to_date: https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/TO_DATE.html#GUID-D226FA7C-F7AD-41A0-BB1D-BD8EF9440118
So you can write TO_DATE('01/20/2021' default '01-01-2020' on conversion error, 'DD-MM-YYYY') or TO_DATE('01/20/2021' default null on conversion error ,'DD-MM-YYYY').
There is also validate_conversion function: https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/VALIDATE_CONVERSION.html#GUID-DC485EEB-CB6D-42EF-97AA-4487884CB2CD
One option is to check date format with regexp_like. Example you posted suggests it is 'dd-mm-yyyy' which means [2 digits - 2 digits - 4 digits]. Certainly, [43-85-0123] "matches" such a format but doesn't represent a valid date. Anyway, see if it helps. In my example, I'm substituting an invalid date value with today's date. Read comments within code.
SQL> with test (col) as
2 -- sample data; the 2nd row is invalid
3 (select 'date-05-03-2020-Tran-100002345-W.44321-CR-9999eu843' from dual union all
4 select 'date-05-032-2020-Tran-100002345-W.44321-CR-9999eu843' from dual
5 ),
6 exdate as
7 -- extract "date" substrings (values between 1st and 4th "-" character)
8 (select col,
9 substr(col, instr(col, '-') + 1,
10 instr(col, '-', 1, 4) - instr(col, '-') - 1
11 ) datum
12 from test
13 )
14 select col,
15 case when regexp_like(datum, '[0-9]{2}-[0-9]{2}-[0-9]{4}') then
16 to_date(datum, 'dd-mm-yyyy')
17 else trunc(sysdate)
18 end as result
19 from exdate
20 /
COL RESULT
---------------------------------------------------- ----------
date-05-03-2020-Tran-100002345-W.44321-CR-9999eu843 05-03-2020
date-05-032-2020-Tran-100002345-W.44321-CR-9999eu843 01-08-2021
SQL>

Oracle 11g date_add

i have a question about the function date_add
i searched a lot in google about the function but the function always have 2 parameters only
but in my exemple it uses 3 parameters ...
the exemple :
date2:=date_add('MM', 1, DPF_DATE_FIN_PRD);
so how does it works ?
There's no DATE_ADD function in Oracle. MySQL has it.
If you want to add any number of days to a date datatype value, you can e.g. (date format is dd.mm.yyyy):
SQL> select trunc(sysdate) + 2 result from dual;
RESULT
----------
07.07.2021
or
SQL> select trunc(sysdate) + interval '2' day as result from dual;
RESULT
----------
07.07.2021
SQL>
As you commented that function exists and works, then it is a custom function so you should review its code and see what it does & what parameters it expects. How? Query user_source. To illustrate it, I created a date_add function in my schema.
SQL> set long 10000
SQL>
SQL> select text
2 from user_source
3 where name = 'DATE_ADD'
4 order by line;
TEXT
-------------------------------------------------------------------------
function date_add (par_datum in date, par_days in number)
return date
is
retval date;
begin
return par_datum + par_days;
end;
7 rows selected.
SQL> select date_add(sysdate, 2) result from dual;
RESULT
----------
07.07.2021
SQL>

Oracle Regular Expression for Date

I have the following anonymous block. I've written a small regular expression to accept the date. It is able to validate the day, month, and year.
Now I want to consider the only century year, and regexp should also allow year in RR format (Century year). Also, I want to accept a day without a zero in the prefix; currently, it is accepting this for the month only. Please see the scenarios below:
> 01/12/2154 (Do not accept, It's not a century year)
> 11/12/1996 (Do not accept, It's not a century year)
> 11/2/24 (Accept, and a plsql logic in IF condition could change it to 2024; Add 20 to it)
> 1/9/2020 (Accept)
> 01/02/2020 (Accept)
> 1/29/20 (Accept)
> 01/11/25 (Accept)
> 1/09/2021 (Accept)
**
declare
date_v varchar2(40):= '01/01/2025';
date_n date;
begin
if regexp_like (date_v, '([0-9]|1[0-2])/([0-2][0-9]|3[0-1])/[0-9]{4}') then
-- logic
date_n:= TO_DATE(date_v,'MM/DD/YYYY');
dbms_output.put_line(date_n);
end if;
end;
You can do a regular expression on a date, but that is not a good way to check if a date is valid, it just checks if the format is ok. For example 30-FEB-2020 will pass your regex but that is not a valid date. The database can do the job for you instead. I usually use something like this:
FUNCTION is_valid_date (date_str_i VARCHAR2, format_i VARCHAR2) RETURN VARCHAR2
/* check if date is valid */
AS
l_dummy_dt DATE;
date_not_valid_for_m EXCEPTION;
PRAGMA EXCEPTION_INIT(date_not_valid_for_m, -01839);
BEGIN
l_dummy_dt := TO_DATE(date_str_i,format_i);
RETURN 'Y';
EXCEPTION WHEN date_not_valid_for_m THEN
RETURN 'N';
END;
Note that it only fails if the TO_DATE returns ora-01839: date not valid for month specified, you can easily add the other possible errors or just use a WHEN OTHERS THEN RETURN 'N';
Oracle is smart enough to recognize the string with or without 0 in date format.
So you can directly convert this string to TO_DATE('11/2/24', 'mm/dd/rrrr') and for recognizing the current century, You can use the TRUNC to century using the 'CC' as follows:
SQL> SELECT
2 TO_DATE('11/2/24', 'mm/dd/rrrr') YOUR_DATE,
3 CASE
4 WHEN TRUNC(TO_DATE('11/2/24', 'mm/dd/rrrr'), 'CC') = TRUNC(SYSDATE, 'CC') THEN
5 'ACCEPT'
6 ELSE
7 'REJECT'
8 END RESULT
9 FROM
10 DUAL;
YOUR_DATE RESULT
----------- ------
02-NOV-2024 ACCEPT
SQL>
Result of the query with another date from the past century:
SQL> SELECT
2 TO_DATE('11/12/1996', 'mm/dd/rrrr') YOUR_DATE,
3 CASE
4 WHEN TRUNC(TO_DATE('11/12/1996', 'mm/dd/rrrr'), 'CC') = TRUNC(SYSDATE, 'CC') THEN
5 'ACCEPT'
6 ELSE
7 'REJECT'
8 END RESULT
9 FROM
10 DUAL;
YOUR_DATE RESULT
----------- ------
12-NOV-1996 REJECT
SQL>
Note: I have used 'rrrr' for a year as it will convert any two-digit years to the year falling in 1950-2049.
Try this one:
with t(date_col) as (
select '01/01/2014' from dual
union all
select '1/2/2014' from dual
union all
select '01/3/2014' from dual
union all
select '1/04/2014' from dual
union all
select '11/1/14' from dual)
select date_col,
case
when regexp_instr(date_col, '^\d/\d/\d{4}$') = 1 then
'd/m/yyyy'
when regexp_instr(date_col, '^\d{2}/\d/\d{4}$') = 1 then
'dd/m/yyyy'
when regexp_instr(date_col, '^\d/\d{2}/\d{4}$') = 1 then
'd/mm/yyyy'
when regexp_instr(date_col, '^\d{2}/\d{2}/\d{4}$') = 1 then
'dd/mm/yyyy'
else
'Unknown format'
end date_format
from t;
DATE_COL DATE_FORMAT
---------- --------------
01/01/2014 dd/mm/yyyy
1/2/2014 d/m/yyyy
01/3/2014 dd/m/yyyy
1/04/2014 d/mm/yyyy
11/1/14 Unknown format
Refer to this link:
Regular expression on Dates in Oracle
Date validation with regular expression is difficult, very difficult. THr problem being that months have differing number of days, and 29-Feb is valid only in certain years. Your request is to have multiple valid formats greatly compounding.
The following function validates dates in the ISO-8601 format (YYYY-MM-DD), and only that format, but it does validate the correct number of days in each month for the dates 0001-01-01 through 9999-12-31, including leap days (29-Feb) when valid. but again just 1 format. Recommendation do not try validating dates with regular expression, esp multiple formats.
create or replace function valid_iso_date (iso_date_string varchar2)
return date
is
iso_date_pattern constant varchar2(256) :=
'^((0[0-9]{2}[1-9]|[1-9][0-9]{3})-((0[13578]|10|12)-(0[1-9]|[12][0-9]|3[01])|02-(0[1-9]|1[0-9]|2[0-8])|(0[469]|11)-(0[1-9]|[12][0-9]|30))$)|^(\d\d(0[48]|[2468][048]|[13579][26])-02-29$)';
result_date date := null;
begin
if regexp_like(iso_date_string, iso_data_pattern)
then
result_date := to_date(iso_date_string,'yyyy-mm-dd');
end if;
return result_date;
end valid_iso_date;

Oracle query to get min or max value of a datatype

Does Oracle have a function or query that will return the min or max value of a datatype? From the documentation I know that the minimum value of a date field is January 1, 4712 BCE. Is there anyway to get that date value from a select statement?
Select ?something? from dual;
If you write a little piece of code, then then answer is yes. Not exactly a single SELECT (unless you put all that into a function), though.
SQL> set serveroutput on;
SQL> declare
2 datum date := trunc(sysdate);
3 begin
4 while 1 <> 2 loop
5 datum := datum - 1;
6 end loop;
7 exception
8 when others then
9 dbms_output.put_line('Last valid date = ' ||
10 to_char(datum, 'dd.mm.yyyy bc'));
11 end;
12 /
Last valid date = 01.01.4712 BC
PL/SQL procedure successfully completed.
SQL>
That was quick (I mean, code takes no time to execute). For other datatypes it isn't that fast (such as which is the smallest valid integer?), at least not by using the same principle.
Use first value in julian calendar
select to_date(1, 'j') from dual
displayed results depends on server and client settings, but it is a date 4712-01-01 BC.
dbfiddle demo

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;