cx_Oracle queries: ORA-00933: SQL command not properly ended - oracle

cur.execute("""
SELECT location, AVG(temp) as avg_temp
FROM (SELECT location,temp, ROWNUM rnum
FROM time_series_location_temp
ORDER BY avg_temp ASC)
WHERE rnum <= 6;
""")
I'm trying to execute this code but keep running into this error DatabaseError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_17344/3055250712.py in
----> 1 cur.execute("""
2 SELECT LOCATION_ID, AVG(temp) as avg_temp
3 FROM (SELECT LOCATION_ID,temp
4 FROM time_series_location_temp
5 ORDER BY temp ASC)
DatabaseError: ORA-00933: SQL command not properly ended
What's wrong and how should I re-write it?
I've tries to rewrite it and still the error comes up. I was expecting that the code would run and execute my query correctly

That error almost invariably means that you have left the semicolon on the end of the statement. This is needed in SQL*Plus but needs to be removed when using cx_Oracle (or the new python-oracledb).

Related

How do I use FETCH FIRST 1 ROWS ONLY in combination with UNION ALL in DB2?

See title.
This is what I'm trying:
select a.work_order_no
from (
select work_order_no as work_order_no
from work_order_line
where insert_timestamp is not null
FETCH FIRST 1 ROWS ONLY
union all
select work_order_no as work_order_no
from work_order_line
where insert_timestamp is null
FETCH FIRST 1 ROWS ONLY
) as a
FETCH FIRST 1 ROWS ONLY
But it give the following error:
SQL State: 42601 Vendor Code: -199 Message: [SQL0199] Keyword UNION not expected. Valid tokens: ). Cause . . . . . :   The keyword UNION was not expected here.  A syntax error was detected at keyword UNION.  The partial list of valid tokens is ). This list assumes that the statement is correct up to the unexpected keyword.  The error may be earlier in the statement but the syntax of the statement seems to be valid up to this point. Recovery  . . . :   Examine the SQL statement in the area of the specified keyword.  A colon or SQL delimiter may be missing. SQL requires reserved words to be delimited when they are used as a name. Correct the SQL statement and try the request again.  Processing ended because the highlighted statement did not complete successfully  Failed statements: 1
In SQL this concept would work with the 'top 1' syntax. I'm assuming this can also work in DB2 but I'm just doing something wrong with the syntax order?
I have asked a colleague and luckily he responded rather quickly:
I missed some ()
select a.work_order_no
from (
(select work_order_no as work_order_no
from work_order_line
where insert_timestamp is not null
FETCH FIRST 1 ROWS ONLY)
union all
(select work_order_no as work_order_no
from work_order_line
where insert_timestamp is null
FETCH FIRST 1 ROWS ONLY )
) as a
FETCH FIRST 1 ROWS ONLY

Merge statement issue - error unable to get a stable set of rows in the source tables

Hi I am getting error while running the below merge statement in oracle db , can you please let me know how to fix the below error ?
--Query
MERGE INTO d_prod_fld dp USING
(SELECT stg_prod_fld_id,
prod_cd_id,
country_name
FROM stg_prod_fld_delta pd
LEFT OUTER JOIN d_loc dl ON (dl.prod_cd_num=lpad(pd.prod_cd_id, 3, '0'))
WHERE pd.efft_to > trunc(sysdate+1)
AND pd.prod_cd_id IS NOT NULL ) stg
ON (dp.cd_id=stg.stg_prod_fld_id)
WHEN matched THEN
UPDATE
SET dl.prod_country=stg.country_name;
d_prod_fld - target dimension table ,
stg_prod_fld_delta - stage table ,
d_loc - look up table
basically when i tried to run the above query in sandbox it is running fine ,but when i tried to run in actual development environment it is showing the above error -
Error starting at line : 1 in command -
Error report -
SQL Error: ORA-30926: unable to get a stable set of rows in the source tables
30926. 00000 - "unable to get a stable set of rows in the source tables"
*Cause: A stable set of rows could not be got because of large dml
activity or a non-deterministic where clause.
*Action: Remove any non-deterministic where clauses and reissue the dml.
This means parallel DML's are happening in the source table stg_prod_fld_delta or lookup table d_loc which are modifying the results of the SELECT query.
You need to acquire a lock on stg_prod_fld_delta and d_loc using select * from table where condition =value for update no wait before running the MERGE statement .
Also issue COMMIT after the MERGE statement.
Please check the below
SELECT *
FROM stg_prod_fld_delta pd
WHERE pd.efft_to > trunc(sysdate+1)
AND pd.prod_cd_id IS NOT NULL
for update no wait;
select * from d_loc dl
for update no wait;
MERGE INTO d_prod_fld dp USING
(SELECT stg_prod_fld_id,
prod_cd_id,
country_name
FROM stg_prod_fld_delta pd
LEFT OUTER JOIN d_loc dl ON (dl.prod_cd_num=lpad(pd.prod_cd_id, 3,
'0'))
WHERE pd.efft_to > trunc(sysdate+1)
AND pd.prod_cd_id IS NOT NULL ) stg ON (dp.cd_id=stg.stg_prod_fld_id)
WHEN matched THEN
UPDATE
SET dl.prod_country=stg.country_name;
COMMIT;

Getting Unknown Command error on IF-THEN-ELSE

I have the following query that I am using in Oracle 11g
IF EXISTS (SELECT * FROM EMPLOYEE_MASTER WHERE EMPID='ABCD32643')
THEN
update EMPLOYEE_MASTER set EMPID='A62352',EMPNAME='JOHN DOE',EMPTYPE='1' where EMPID='ABCD32643' ;
ELSE
insert into EMPLOYEE_MASTER(EMPID,EMPNAME,EMPTYPE) values('A62352','JOHN DOE','1') ;
END IF;
On running the statement I get the following output:
Error starting at line : 4 in command -
ELSE
Error report -
Unknown Command
1 row inserted.
Error starting at line : 6 in command -
END IF
Error report -
Unknown Command
The values get inserted with error when I run it directly. But when I try to execute this query through my application I get an oracle exception because of the error generated :
ORA-00900: invalid SQL statement
And hence the values are not inserted.
I am relatively new to Oracle. Please advise on what's wrong with the above query so that I could run this query error free.
If MERGE doesn't work for you, try the following:
begin
update EMPLOYEE_MASTER set EMPID='A62352',EMPNAME='JOHN DOE',EMPTYPE='1'
where EMPID='ABCD32643' ;
if SQL%ROWCOUNT=0 then
insert into EMPLOYEE_MASTER(EMPID,EMPNAME,EMPTYPE)
values('A62352','JOHN DOE','1') ;
end if;
end;
Here you you the update on spec, then check whether or not you found a matching row, and insert in case you didn't.
"what's wrong with the above query "
What's wrong with the query is that it is not a query (SQL). It should be a program snippet (PL/SQL) but it isn't written as PL/SQL block, framed by BEGIN and END; keywords.
But turning it into an anonymous PL/SQL block won't help. Oracle PL/SQL does not support IF EXISTS (select ... syntax.
Fortunately Oracle SQL does support MERGE statement which does the same thing as your code, with less typing.
merge into EMPLOYEE_MASTER em
using ( select 'A62352' as empid,
'JOHN DOE' as empname,
'1' as emptype
from dual ) q
on (q.empid = em.empid)
when not matched then
insert (EMPID,EMPNAME,EMPTYPE)
values (q.empid, q.empname, q.emptype)
when matched then
update
set em.empname = q.empname, em.emptype = q.emptype
/
Except that you're trying to update empid as well. That's not supported in MERGE. Why would you want to change the primary key?
"Does this query need me to add values to all columns in the table? "
The INSERT can have all the columns in the table. The UPDATE cannot change the columns used in the ON clause (usually the primary key) because that's a limitation of the way MERGE works. I think it's the same key preservation mechanism we see when updating views. Find out more.

How to create an Oracle stored procedure with a parameter?

I'm a novice at SQL and am trying to create a Stored Procedure in Oracle database. The SPROC needs two date parameters (from_date and to_date) for my report to run. Maybe I'm confusing this with SQL Server code.
My code looks like this:
CREATE PROCEDURE uSP_RevPerSalesman
#from_date DATE
#to_date DATE
AS
BEGIN
SELECT DISTINCT
C.CUSTOMER_CODE
, MS.SALESMAN_NAME
, SUM(C.REVENUE_AMT)
FROM
C_REVENUE_ANALYSIS C
, M_CUSTOMER MC
, M_SALESMAN MS
WHERE
C.CUSTOMER_CODE = MC.CUSTOMER_CODE AND
MC.SALESMAN_CODE = MS.SALESMAN_CODE AND
MC.COMP_CODE = 'W1' AND
MS.COMP_CODE = '00' AND
C.REVENUE_DATE >= :from_date AND
C.REVENUE_DATE <= :to_date
GROUP BY
C.CUSTOMER_CODE, MS.SALESMAN_NAME
ORDER BY
C.CUSTOMER_CODE
END
GO
I get an error message when I run this code. The error message I get is:
ERROR ORA-00900: invalid SQL statement
When I run only the SELECT code, it works and gives me the right results. I just can't seem to make this into a SPROC.
Remove the GO, that is not valid in Oracle. Try a semicolon at the end instead, or a /, depending on where you're running this.

oracle SQL and ( ) brackets in where

I have an application which automatically add brackets after WHERE condition and send it to JDBC Oracle driver, Oracle doesn't like it and thrown: ORA-00907: missing right parenthesis
I'm not sure how to work with it in the scope of Oracle syntax, but any suggestion to fix it having this brackets or it's not supported by the syntax?
Original query works just fine:
SELECT count(*) as ErrorCount, Engine_name, to_char(log_time,'hh24') as Hour FROM eailog_data.err_log WHERE err_timestamp > sysdate-1/24 GROUP BY engine_name, to_char(log_time,'hh24') HAVING count(*) > 100 AND count(*) > 0 ORDER BY count(*)
and 3rd party application modify it like this (note brackets added after WHERE condition):
SELECT count(*) as ErrorCount, Engine_name, to_char(log_time,'hh24') as Hour
FROM eailog_data.err_log
WHERE
(
err_timestamp > sysdate-1/24
GROUP BY engine_name,
to_char(log_time,'hh24')
HAVING count(*) > 100
)
AND count(*) > 0
ORDER BY count(*)
Any ideas how to fix SQL with added brackets?
The WHERE clause parenthetical expression needs to end at the end of the WHERE clause and the condition in the HAVING clause ends with a parenthesis, but never begins.
In terms of adding parenthesis, certainly you could add a parenthesis at the end of the WHERE clause and add a parenthesis at the beginning of the HAVING clause as follows:
SELECT count(*) AS errorcount,
engine_name,
to_char(log_time,'hh24') AS HOUR
FROM eailog_data.err_log
WHERE ( err_timestamp > SYSDATE-1/24 )
GROUP BY engine_name,
to_char(log_time,'hh24')
HAVING ( count(*) > 100 )
AND count( *) > 0
ORDER BY count(*)
Since this is an application, it sounds like you need to work with the author of the application to fix their parenthesis usage.
Here is an example using the DUAL table
Before, malformed parenthetical expression in the WHERE and HAVING clause.
SCOTT#dev> SELECT dummy,
2 COUNT(*)
3 FROM dual
4 WHERE (dummy != 'Y'
5 GROUP BY dummy
6 HAVING COUNT( *) = 1)
7 AND COUNT( *) > 0
8 ORDER BY COUNT(*)
9 /
WHERE (dummy != 'Y'
*
ERROR at line 4:
ORA-00907: missing right parenthesis
After, corrected parenthetical expression in the 'WHERE' and 'HAVING' clause.
SCOTT#dev> --corrected
SCOTT#dev> SELECT dummy,
2 COUNT(*)
3 FROM dual
4 WHERE (dummy != 'Y')
5 GROUP BY dummy
6 HAVING (COUNT( *) = 1)
7 AND COUNT( *) > 0
8 ORDER BY COUNT(*)
9 /
D COUNT(*)
= ==========
X 1
A SQL statement consists of several clauses (some of which are optional):
the column list
the table list (FROM clause)
filter conditions (WHERE clause)
aggregate columns (GROUP BY clause)
aggregate conditions (HAVING clause)
etc.
The key concept that seems to be missing is that you can't open a parenthesis in one clause and close it in another. The reason the error you're getting is "missing right parenthesis" is that the SQL engine thinks you're done with the WHERE clause as soon as it sees GROUP BY. Since there was a un-closed parenthetical at that point, it can't parse any further.
To use an analogy, the SQL you provided is like having the opening and closing parenthesis in different methods in Java. It simply can't work.
There are at least two ways to get around some tool mangling your SQL syntax: Creative SQL to subvert the parser, and convert the SQL.
Creative SQL
Parsing Oracle SQL is virtually impossible to do 100% correctly since the syntax is much more complicated than other languages. This leads to problems with beautifiers and code generators. I've seen tools fail in ways very similar to your example.
But this complexity also offers many opportunities to subvert tools that try to rewrite SQL. Try different features until you find something that is immune to their parser. Here are some ideas:
Inline view. select * from (select ... from ... where ... ) where 1=1;
Common table expression. with some_query as (select ... from ... where ... ) select * from some_query;
Alternative quoting mechanism.
select dummy
from dual
where '''' = q'<'>' --The parser probably thinks this is still a string.
and 1 = 1
group by dummy
--' --And it probably thinks this is the end.
Convert SQL
In extreme cases there are ways to make Oracle accept completely broken SQL. Check out
SQL Translation Framework
and DBMS_ADVANCED_REWRITE.
Those tools are definitely a last resort. It would be great if we could wave a magic wand and fix all 3rd party programs but we have to live in the real world.

Resources