ora-00933 sql command not properly ended INNER JOIN - SUBQUERY -DATE - oracle

my Query ended with the Error "ora-00933 sql command not properly ended"
The Query:
create table tmp_cleaner
as (
SELECT dd.bigtriggerid
FROM documentdata dd
inner join ipl_bigtrigger bt on dd.bigtriggerid = bt.triggerid
inner join documentinfo di on dd.bigtriggerid = di.bigtriggerid
where bt.processed = 'T'
and di.status in (1, 2)
and bt.processdatetime <= add_months(sysdate, -3));
Delete FROM documentdata where exists (select bigtriggerid from tmp_cleaner where bigtriggerid = documentdata.bigtriggerid);
Error in Line 9. (last line)
ora-00933 sql command not properly ended
Where is my mistake? should i use trunc with date?
I tried to put the Join-Operators in ()

There's nothing wrong with that code.
Sample tables:
SQL> create table documentdata as select 1 bigtriggerid from dual;
Table created.
SQL> create table ipl_bigtrigger as select 1 triggerid, 'T' processed, date '2022-02-25' processdatetime from dual;
Table created.
SQL> create table documentinfo as select 1 bigtriggerid, 1 status from dual;
Table created.
Your query, as is:
SQL> CREATE TABLE tmp_cleaner
2 AS
3 (SELECT dd.bigtriggerid
4 FROM documentdata dd
5 INNER JOIN ipl_bigtrigger bt ON dd.bigtriggerid = bt.triggerid
6 INNER JOIN documentinfo di ON dd.bigtriggerid = di.bigtriggerid
7 WHERE bt.processed = 'T'
8 AND di.status IN (1, 2)
9 AND bt.processdatetime <= ADD_MONTHS (SYSDATE, -3));
Table created.
SQL> select * from tmp_cleaner;
BIGTRIGGERID
------------
1
SQL>
Could you provide some context? Where did you run that piece of code?
There's nothing wrong with delete either (apart from the fact that you're using a new table in the subquery; shouldn't that be tmp_cleaner you've just created?):
SQL> Delete FROM documentdata
2 where exists (select bigtriggerid
3 from tmp_cleaner -- tmp_loeschbigtrigger
4 where bigtriggerid = documentdata.bigtriggerid);
1 row deleted.
SQL>

Related

(Oracle)Correlated subquery usage

Subquery query1 below works fine.
But when I put equi condition in -sort of- nested clause like query2, it shows error ORA-00904.
Is this wrong usage of correlated subquery or it is because of other reason?
--Query1: It shows expected result.
SELECT
O.ENAME
O,SAL
,(SELECT COUNT(*)
FROM SCOTT.EMP I
WHERE I.SAL>O.SAL --correlated to outer
) AS RESULT
from SCOTT.EMP O;
--Query2:ORA-00904: "O"."SAL": invalid identifier shows. How to modify to use correlated subquery?
SELECT
O.ENAME
O,SAL
,(
WITH TEMP AS
(
SELECT COUNT(*)
FROM SCOTT.EMP I
WHERE I.SAL>O.SAL --I have put equi condistion here
)
SELECT * FROM TEMP
) AS RESULT
from SCOTT.EMP O;
I believe the second option is a wrong use of correlated subqueries, not because of the comparison, but for the use of the with clause. I would like to remember that you should avoid correlated subqueries as much as possible.
The WITH clause, or subquery factoring clause, may be processed as an inline view or resolved as a temporary table. The advantage of the latter is that repeated references to the subquery may be more efficient as the data is easily retrieved from the temporary table, rather than being requeried by each reference.
In your third column of your second query you want to get the result from the inline view. The problem is that parsing of the inline view is done independently and therefore cannot have references to anything in the outer query.
SQL> create table emp ( ename varchar2(10) , sal number ) ;
Table created.
SQL> insert into emp values ( 'AAA' , 1000 ) ;
insert into emp values ( 'BBB' , 1000 ) ;
insert into emp values ( 'CCC' , 1000 ) ;
insert into emp values ( 'DDD' , 1000 ) ;
1 row created.
SQL> SQL>
1 row created.
SQL> SQL>
1 row created.
SQL> SQL>
1 row created.
SQL> select * from emp ;
ENAME SAL
---------- ----------
AAA 1000
BBB 1000
CCC 1000
DDD 1000
To write the query with inline view, the filter must be done in the outer query
SELECT
O.ENAME
O,SAL
,(
WITH TEMP AS
(
SELECT * FROM EMP
)
SELECT count(*) FROM TEMP t WHERE t.SAL>O.SAL
) AS RESULT
from EMP O;
O SAL RESULT
---------- ---------- ----------
AAA 1000 0
BBB 1000 0
CCC 1000 0
DDD 1000 0
It has been explained that the second query does not uses with correctly.
Let me suggest, however, that your query can be simpler and more efficiently phrased. For each employee, you want to count how many employees have a greater salary. Window functions are the way to go here:
select e.*, rank() over(order by salary desc) - 1 result
from scott.emp e

How to return 0 incase of empty result in oracle select query?

I have a Query where there is number datatype column. In case of empty resultset O/P is blank. I want 0 in that case.
My query is
select nvl(infodata,0)
from table1
where group_id = 111
and appid in (select max(id)
from table1, table2
where status = 'A');
Now my inner query is returning null in that case. NVL seems to be not working on infodata column. Please help
Outcome of such a query is no rows selected.
For example (based on Scott's EMP and DEPT tables as I don't have yours, and you didn't post test case), this query returns nothing:
SQL> select e.deptno
2 from emp e
3 where e.ename = 'Littlefoot';
no rows selected
If it is used as a subquery, the result is equal to what you currently have:
SQL> select nvl(d.dname, 'x') result
2 from dept d
3 where d.deptno in (select e.deptno
4 from emp e
5 where e.ename = 'Littlefoot'
6 );
no rows selected
But, if you apply aggregation (see line #1), then you'd get what you wanted:
SQL> select nvl(max(d.dname), 'x') result
2 from dept d
3 where d.deptno in (select e.deptno
4 from emp e
5 where e.ename = 'Littlefoot'
6 );
RESULT
--------------
x
As I said: it works on my test case; might, or might not on yours. If you post sample data, we'd have something to work with.

oracle sql update with sub select

I want to update 1 field of the last 2 rows of a table. So I need a subquery.
Both sql works - how can I combine these 2 SQL commands?
select command (works, last 2 rows):
SELECT * FROM (select * from mytable WHERE id='62741' ORDER BY lfdnr DESC) mytable2 WHERE rownum <= 2;
Result:
LFDNR ID M2
361782 62741 8,5
361774 62741 8,6
Update (?, exists, in, merge ?)
UPDATE mytable set m2='8,4' WHERE EXISTS (select * from mytable WHERE id='62741' and rownum <=2 ORDER BY lfdnr DESC);
Result:
Fehlerbericht -
SQL-Fehler: ORA-00907: missing right parenthesis
00907. 00000 - "missing right parenthesis"
*Cause:
*Action:
Thank you for helping me!
Michael
You could use rowid pseudocolumn:
update mytable set m2 = '8, 4'
where rowid in (select rowid
from (
select rowid, row_number() over (order by lfdnr desc) rn
from mytable where id = '62741')
where rn <= 2 )
Test:
create table mytable (id varchar2(5), lfdnr number(5), m2 varchar2(10));
insert into mytable values ('62705', 1, 'abc');
insert into mytable values ('62741', 2, 'xyz');
insert into mytable values ('62741', 3, 'qwe');
insert into mytable values ('62741', 4, 'rty');
ID LFDNR M2
----- ------ ----------
62705 1 abc
62741 2 xyz
62741 3 8, 4
62741 4 8, 4

Correctly use collection method

CREATE OR REPLACE TYPE nvarchar2_list_type AS TABLE OF NVARCHAR2(100);
CREATE TABLE test_table(
id number primary key,
cars_list nvarchar2_list_type
)
NESTED TABLE cars_list STORE AS cars_list_storage_table;
insert into test_table(id, cars_list)
values(1, nvarchar2_list_type( 'AUDI', 'MERCEDES') );
All above operations completed success, 1 rows inserted in table test_table, now i write this function:
create or replace function get_cnt
return number
as
ret_val number;
begin
SELECT cars_list.COUNT
INTO ret_val
from test_table where id = 1;
return ret_val;
end;
This gives error: ORA-00904: "CARS_LIST"."COUNT": invalid identifier
Tell please what is wrong here?
As I know, COUNT method must be used just so (from here)
No, you cannot use count method in this situation. You have SQL nested table at hand, count method is used only with PL/SQL collections.
To count number of nested table's elements you can either unnest that nested table or use scalar sub-query:
Unnesting:
SQL> select id
2 , count(*) as cnt
3 from test_table t
4 cross join table(t.cars_list)
5 group by id
6 ;
ID CNT
---------- ----------
1 2
Scalar sub-query:
SQL> select id
2 , (select count(column_value)
3 from table(t.cars_list)) as cnt
4 from test_table t
5 ;
ID CNT
---------- ----------
1 2
Use
Select
Cardinality(cars_list) from test_table
I can't explain why that doesn't work, but this does:
select (select count(*) from table(cars_list))
into ret_val
from test_table
where id = 1;
Oracle is expecting column name or function in its select list, but what you are giving is collection build in method that operates on collections only.
You can achieve the same using scalar sub query
SELECT (select count(1) from table(cars_list)) as "COUNT"
FROM test_table
WHERE id = 1;

Delete with Left Join in Oracle 10g

I have the following code that works fine in MS SQL Server:
delete grp
from grp
left join my_data
on grp.id1 = my_data.id1
and grp.id2 = my_data.id2
and grp.id3 = my_data.id3
and grp.id4 = my_data.id4
where my_data.id1 is NULL
Basically, I want to delete all occurrence that can be found in grp and don't have any equivalence in my_data. Sadly, it doesn't work in Oracle 10g. I tried using the old syntax for left join (+) but it doesn't work either. Like this:
delete grp
from grp,
my_data
where grp.id1 = my_data.id1 (+)
and grp.id2 = my_data.id2 (+)
and grp.id3 = my_data.id3 (+)
and grp.id4 = my_data.id4 (+)
and my_data.id1 is NULL
A IN clause would works if I didn't have multiple keys but I don't see how I could use it with my data. So, what is the alternative?
Shannon's solution is the way to go: use the operator NOT IN (or NOT EXISTS).
You can however delete or update a join in Oracle, but the synthax is not the same as MS SQL Server:
SQL> DELETE FROM (SELECT grp.*
2 FROM grp
3 LEFT JOIN my_data ON grp.id1 = my_data.id1
4 AND grp.id2 = my_data.id2
5 AND grp.id3 = my_data.id3
6 AND grp.id4 = my_data.id4
7 WHERE my_data.id1 IS NULL);
2 rows deleted
Additionally, Oracle will only let you update a join if there is no ambiguity as to which base row will be accessed by the statement. In particular, Oracle won't risk an update or a delete (the statement will fail) if there is a possibility that a row may appear twice in the join. In this case, the delete will only work if there is a UNIQUE constraint on my_data(id1, id2, id3, id4).
Tables and data:
SQL> create table grp (id1 number null, id2 number null, id3 number null, id4 number null);
Table created.
SQL> create table my_data (id1 number null, id2 number null, id3 number null, id4 number null);
Table created.
SQL> insert into grp values (1, 2, 3, 4);
1 row created.
SQL> insert into grp values (10, 20, 30, 40);
1 row created.
SQL> insert into grp values (1, 2, 30, 40);
1 row created.
SQL> insert into my_data values (1, 2, 3, 4);
1 row created.
SQL> commit;
Commit complete.
Using in. Note Do not use if the IDs in the subquery can be null. Not in of null never returns true.
SQL> delete grp where (id1, id2, id3, id4) not in (select id1, id2, id3, id4 from my_data);
2 rows deleted.
SQL> select * from grp;
ID1 ID2 ID3 ID4
---------- ---------- ---------- ----------
1 2 3 4
Using exists
SQL> rollback;
Rollback complete.
SQL> delete grp where not exists (select * from my_data where grp.id1 = my_data.id1 and grp.id2 = my_data.id2 and grp.id3 = my_data.id3 and grp.id4 = my_data.id4);
2 rows deleted.
SQL> select * from grp;
ID1 ID2 ID3 ID4
---------- ---------- ---------- ----------
1 2 3 4
SQL>
If you want to ensure there is no ambiguity in what's being deleted, you could change Vincent's solution to:
delete from grp where rowid in
(
select
grp.rowid
from
grp left outer join my_data on
grp.id1 = my_data.id1
and grp.id2 = my_data.id2
and grp.id3 = my_data.id3
and grp.id4 = my_data.id4
where
my_data.id1 is NULL
)
Either Vincent's answer https://stackoverflow.com/a/3675205 does not work at all, or it does not work in Oracle 12c. That answer should be improved by specifying the lowest or highest version of Oracle where this works. The proof:
SELECT * FROM v$version where banner like 'Oracle%';
/*
Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production
*/
create table a (id int);
create table b (id int);
insert into a select 1 from dual union select 2 from dual;
insert into b select 1 from dual union select 2 from dual union select 3 from dual;
select * from a right join b on b.id = a.id;
/*
1 1
2 2
null 3
*/
delete from (
select b.*
from b
inner join a on a.id = b.id
)
/*
Error at Command Line : 7 Column : 13
Error report -
SQL Error: ORA-01752: cannot delete from view without exactly one key-preserved table
01752. 00000 - "cannot delete from view without exactly one key-preserved table"
*Cause: The deleted table had
- no key-preserved tables,
- more than one key-preserved table, or
- the key-preserved table was an unmerged view.
*Action: Redefine the view or delete it from the underlying base tables.
*/
delete from b
where rowid in (
select b.rowid
from b
inner join a on a.id = b.id
)
/*
2 rows deleted.
*/
select * from a right join b on b.id = a.id
/*
null 3
*/
drop table a;
drop table b;
Bottom line is, use WHERE ROWID IN () at least in 12c.
I can't add a comment because it need 50 reps,so I add a answer here.
I tested Vincent's delete from query, that syntax can't let you delete what you want,at least it's not a common use for all the delete join cases.
At first I create a table using oracle default user scott:
create table emp1 as select * from emp where sal<2000;
I want to delete the records from emp where empno in emp1(just a simple test),so I used this delete from query:
delete from (select a.* from emp a join emp1 b on a.empno=b.empno);
No matter what the table or join order is,left join or inner join,no matter what where clause I use,the sql will delete the corresponding records in emp1.
So I think this delete from query can not let you delete from a specified table.
Loop a cursor will be a better way for these cases.

Resources