Reputation: 5213
I have got this SQL, it yields ORA-00920 Invalid relational operator
error, what is wrong and how can I fix this?
select * from my_tab where (a,b,c,t) in
( select a,b,c, max(t) as t from my_tab where foo<>'bar'
group by a,b,c
order by t
) and rownum between 20 and 30
(also tried rownum>20 and rownum<30
)
DDL:
create table my_tab
(a number,
b number,
c number,
t date,
foo varchar2(20),
buzz varchar2(2000)
);
There is no index in the table.
I want to read the whole table actually, but since there are many rows, I want to process in chunks. I cannot add column to the table (for example a unique id or a counter to hold the progress).
Upvotes: 1
Views: 116
Reputation: 1523
The problem is that you have 3 values before the in clause and 4 columns coming from the subquery.
This code might help you.
WITH my_tab AS (
SELECT 'a' AS a,
'b' AS b,
'c' AS c,
1 AS t,
'bar!' AS foo
FROM dual
)
SELECT * FROM (
SELECT t.*, ROWNUM AS RN FROM my_tab t WHERE ('a','b','c') IN
(
SELECT a,b,c FROM (
select a,b,c, max(t) as t
from my_tab where foo <> 'bar'
group by a,b,c
order by t
)
)
)
WHERE RN between 0 and 1
Copy and paste this code into your oracle client and see the result. I think it will work as you expect.
If you want to filter using the t value, the query below might be useful:
WITH my_tab AS (
SELECT 'a' AS a,
'b' AS b,
'c' AS c,
1 AS t,
'bar!' AS foo
FROM dual
)
SELECT * FROM (
SELECT t.*, ROWNUM AS RN FROM my_tab t WHERE ('a','b','c', 1) IN
(
SELECT a,b,c,t FROM (
select a,b,c, max(t) as t
from my_tab where foo <> 'bar'
group by a,b,c
order by t
)
)
)
WHERE RN between 0 and 1
This code only works using rownum between 0 and 1
(RN) since there is just one row in my_tab.
Upvotes: 0
Reputation: 17944
Either of these will work:
select * from my_tab
where (a,b,c,t) in
( select a,b,c,t from
( select a,b,c, max(t) as t, row_number() over ( order by max(t)) rn
from my_tab
where foo<>'bar'
group by a,b,c
)
where rn between 20 and 30
) ;
(in 12c only...)
select * from my_tab
where (a,b,c,t) in
( select a,b,c, max(t) as t
from my_tab
where foo<>'bar'
group by a,b,c
offset 19 rows
fetch next 11 rows only -- should give you rows 20 thru 30, a weird window of 11 rows
);
I want to read the whole table actually, but since there are many rows, I want to process in chunks.
If you try to do it this way, you'll be re-reading the whole table for every chunk! If you post some more details about what you are trying to do (probably a separate question would be appropriate), someone here can probably help you avoid that with a different approach.
Upvotes: 1
Reputation: 50047
There are a couple of problems here:
(a,b,c,t) IN (...subquery...)
. You'll need to do an INNER JOIN of the subquery.ROWNUM BETWEEN 20 AND 30
will never return any data. ROWNUM is not generated until a row is emitted from the query, so the first row emitted from the query always has ROWNUM = 1. The problem here is that you're waiting for a row with ROWNUM = 20 to be emitted - but none of the preceding rows have ever been generated. Thus, no data. The workaround for this is to pull all the rows in a subquery, then look for the appropriate rows in an outer query.Put together, we get:
WITH cteData AS (SELECT A, B, C, MAX(T) AS MAX_T
FROM MY_TAB
WHERE FOO <> 'bar'
GROUP BY A, B, C
ORDER BY MAX(T))
SELECT *
FROM (SELECT mt.*, ROWNUM AS RN
FROM MY_TAB mt
INNER JOIN cteData d
ON d.A = mt.A AND
d.B = mt.B AND
d.C = mt.C AND
d.MAX_T = mt.T) sq
WHERE sq.RN BETWEEN 20 AND 30
Upvotes: 2
Reputation: 2584
The solution is mentioned in the comments, but just to summarize: Two things to be done here. 1) Add t to the where condition 2) Remove the order by in the subquery:
SELECT *
FROM my_tab
WHERE (a,b,c,t) IN
(select a,b,c, max(t) as t from my_tab where foo<>'bar'
group by a,b,c)
and rownum between 20 and 30;
Hope this helps.
Upvotes: 0