Using Where Clause with Dates When Reading SQL Query in R - sql

I am attempting to query an Oracle datebase from R using the SQL function found here.
When I complete an easy query, such as
'SELECT * FROM TABLE_1'
the query executes fine. However, when I add a conditional date statement to the query, such as
'SELECT * FROM TABLE_1 WHERE START_DT BETWEEN '01-JUL-2018' AND '30-JUN-2019'
I get the following error message:
Error in .oci.SendQuery(conn, statement, data = data, prefetch =
prefetch, : ORA-00904: "30-JUN-2019": invalid identifier
Any idea how I can fix this?

The exact error appears to be that you didn't escape the single quotes you placed around the date literals in your R query string. But, fixing that still leaves the problem that your date literals are invalid for Oracle. I recommend using this:
sql <- "SELECT * FROM TABLE_1 WHERE START_DT BETWEEN DATE '2018-07-01' AND DATE '2019-06-30'"
You could also use the TO_DATE function, e.g. TO_DATE('01-JUL-2018', 'DD-MON-YYYY'), but this is a bit harder to read than using the DATE keyword.

Related

ORACLE QUERY to pass date as variable in TOAD

I'm new to oracle and trying to run a simple query to pass date dynamically
DEFINE startdate = TO_DATE(select TRUNC(LAST_DAY(ADD_MONTHS( max(nav_last_calc_dt) ,-1))+1) from tb);
DEFINE enddate = TO_DATE(select TRUNC(LAST_DAY(ADD_MONTHS(max(nav_last_calc_dt),0))) from tb);
begin
select Count(1)
FROM tb
WHERE DATE BETWEEN &startdate AND &enddate;
end;
I received the below error when executing using script (F5), TOAD script runner.
ORA-06550: line 4, column 78:
PL/SQL: ORA-00936: missing expression
ORA-06550: line 2, column 1:
PL/SQL: SQL Statement ignored
But when using SQL PLUS , it returned 7 as result. So I'm confused.
SQL*Plus isn't returning 7 as the result; you haven't completed the anonymous PL/SQL block, so it is showing you 7 as the next line number (as 'begin' is line 1 and 'end;' is line 6, and is waiting for input. If you enter a slash and hit return it will then execute the block; which will throw the same ORA-00936 error.
In both clients the problem is the DATE keyword - it's expecting that to be the start of a date literal, and doesn't see the rest of the literal value as it expects. That should be a column name, presumably:
WHERE nav_last_calc_dt DATE BETWEEN &startdate AND &enddate;
But the block will still fail, possibly for different reasons in the two clients; in SQL*Plus it will still get ORA-00936 because the defined value ends at the first space (which you can fix by enclosing in double quotes), and Toad may throw that error or complain that your select has no 'into' clause. (Or it might do something else; SQL Developer against 12cR1 is throwing an internal error.) The outer TO_DATE in your defined expressions is also not ideal - it will implicitly convert the date you have to a string and then convert that string back again to a real date, both using your session NLS settings; which might work, but isn't needed.
It's not clear why you are using PL/SQL there, or really why you are using a substitution variable - it's not really dynamic, it just makes the final statement a bit more obscure.
The date calculation also seems a bit complicated. It looks like you're trying to count rows from the last month with any data; and you're finding the first day of that month using add_months and last_day - which could be done more simply just by truncating the maximum date using the 'MM' date component:
select count(*)
from tb
where nav_last_calc_dt >= (select trunc(max(nav_last_calc_dt), 'MM') from tb)
Assuming the column used for the filter is `nav_last_calc_dt, and not some other column, you don't need an upper bound - you know the maximum date is in that month, so it has to be within the month.
If if was another column, with later dates, and you used between then you would exclude any values after midnight on the last day of that month. It's safer to use a full month range:
select count(*)
from tb
where some_date >= (select trunc(max(nav_last_calc_dt), 'MM') from tb)
and some_date < (select add_months(trunc(max(nav_last_calc_dt), 'MM'), 1) from tb)
which would find all values at or after midnight on the first day of the target month, and before midnight on the first day of the following month.
It might then be worth getting the maximum date once, but you could do that in a CTE or an inline view rather than via define, which wouldn't actually save you anything the way you are trying to use it - since both defined queries would be substituted into the query/block before it's executed.

How to use bind variables for date literals?

Consider the following SQL
SELECT * FROM employee WHERE dob = DATE '1980-05-15'
I need to rewrite the query to get rid of the hard coded values and use bind variables instead. So, my rewritten query looks like this
SELECT * FROM employee WHERE dob = DATE :dateOfBirth
However, the query doesn't work. I've tried all possible formats (1980-05-15, 15-MAY-80, 15-MAY-1980) for :dateOfBirth variable, without any luck. I always get ORA-00936: missing expression error.
Note 1: I'm aware of to_date() function that can solve my issue, but I can't use that because the query originates from a different system on which I don't have any control over.
Note 2: DD-MON-RR is the nls_date_format in my database as specified in nls_session_parameters & nls_database_parameters
You can't, you need to to_date it:
SELECT * FROM employee WHERE dob = to_date ( :dateOfBirth, '<fmt>' );

cx_Oracle.DatabaseError: ORA-01843: not a valid month

select distinct sko.CONTENTId,
sko.HELPDESKID,
sko.SEGMENTID,
som.SUBMITTED_FOR_NAME,
sko.SUBMITTEDDATE,
to_date(sko.LASTMODIFIEDDATE, 'DD-MM-RR')
from sky_know_obj sko
join sky_object_mass som
on sko.CONTENTId = som.CONTENTId
where sko.LASTMODIFIEDDATE > date'2019-11-03'
and sko.LASTMODIFIEDDATE <= date'2019-12-03'
This is my oracle sql query. i am running it in python. when I run this in the Oracle SQL Developer then it is giving results but whenever I tried to execute it in the pycharm the following error is occuring:
cx_Oracle.DatabaseError: ORA-01843: not a valid month
when I run
select * from nls_session_parameters;
this in oracle sql developer then its showing
NLS_DATE_FORMAT = DD-MM-RR
As you apply TO_DATE to LASTMODIFIEDDATE column and it fails, it seems that not all values have valid month in that column which means that its datatype isn't date but varchar2.
SQL Developer doesn't return all rows, but the first 50 (or so). If your query scans the whole table, or rows that weren't displayed initially, then it'll fail. Try to navigate to the last row in returned record set in SQL Developer to see what happens.
On the other hand, if column's datatype is date, then don't to_date it; there's no point in doing that.
Also, you shouldn't rely on database's settings. Take control over your data and don't specify string when meaning date. Use date literal, e.g.
where lastmodifieddate > date '2019-11-03' -- instead of '03-11-19'

Date Formats in SQL

((SELECT ES.MCH_POS
FROM IFSAPP.EQUIPMENT_SERIAL ES
WHERE ES.CONTRACT = W.CONTRACT
AND ES.MCH_CODE = W.MCH_CODE), 'yyyy/mm/dd') as SALE_DATE
When I run this code an error is occurred as ORA-00907: missing right parenthesis
ORA-00907: missing right parenthesis
This is a syntax error. Occasionally it really does mean we have a unpaired left parenthesis. More often it means we have made a bloomer, and we have a keyword or expression where the compiler expected a closing ). Sometimes it just points to a typo.
, 'yyyy/mm/dd' is a format mask, used in casting a string to a date or a date to string. However, your snippet has no TO_DATE() or TO_CHAR() function, so I'm guessing that's your problem. You have a format mask where the compiler thinks there should be just a ).
With just a subquery to go on it's hard to be sure but probably what you want is something like this:
(SELECT to_char(ES.MCH_POS, 'yyyy/mm/dd') as SALE_DATE
FROM IFSAPP.EQUIPMENT_SERIAL ES
WHERE ES.CONTRACT = W.CONTRACT
AND ES.MCH_CODE = W.MCH_CODE)
If this is not the exact solution you require and doesn't help you get to it please edit your question to include more details regarding the problem you are trying to solve.
In Oracle you need the to_char() function
TO_CHAR(date-value,'date-format-mask')
From your code snippet it should look more along these lines 9I think):
select ....
, to_char((SELECT ES.MCH_POS
FROM IFSAPP.EQUIPMENT_SERIAL ES
WHERE ES.CONTRACT = W.CONTRACT
AND ES.MCH_CODE = W.MCH_CODE
AND rownum = 1), 'yyyy/mm/dd') as SALE_DATE
i.e. the correlated subquery returns one date value, and that date value is then formatted as yyyy/mm/dd
nb: I threw in the and rownum = 1 because as you see it above, that correlated subquery MUST only return a single date value.

Oracle: between dates statement gives error 'not valid month'

I'm not sure what I'm doing wrong here. I'm trying to build an oracle query that I will be executing from my php project via oci. I need to select all records between a specific date range.
In trying to get the syntax down, I wrote out this test query:
SELECT * FROM SHIPPED
WHERE user_seq_id = 381 AND
LOT_DATE BETWEEN TO_DATE('05/27/2014', 'MM/DD/YYYY')
AND TO_DATE('06/03/2014','MM/DD/YYYY');
This syntax seems like it should work but it's not. I'm definitely not an oracle developer so I'm positive I"m misunderstanding something. When I've looked at similar posts I haven't found anything that would point to what I'm doing wrong.
This is a rather tricky error. The problem would occur if LOT_DATE were stored as a character string rather than a date -- and the string contained invalid data.
By explicitly converting the right hand side of the comparison to dates, the comparison is attempted by converting the field to a date. And there is an error.
The fix is to fix the data in the field. if something is in a field called "date", then it should probably have a date data type.
For identifying unsupported string value for date - You can create a PL/SQL function which accepts string and validate for correct date format, sample of function:
CREATE OR REPLACE FUNCTION VERIFY_DATE(v_date IN VARCHAR2) RETURN NUMBER IS
v_date1 DATE;
BEGIN
select to_date(v_date) into v_date1 from dual;
RETURN 1;
Exception WHEN Others THEN
RETURN 0;
END;
Now, identify rows which are having invalid string value for which you should correct to run your query:
select * from
(
select VERIFY_DATE(LOT_DATE) DateVerified,s.* from SHIPPED s
)
where
DateVerified=0