Reputation: 923
I have a table col
where i have:
select * from offc.col;
I returned some data using query by year wise ans dept_id wise:
SELECT dept_id,
year,
Max(marks) marks
FROM offc.col
GROUP BY dept_id,
year
ORDER BY dept_id,
year
The data I got was:
Here there is no problem as my sql is running right.So, I needed to extract all the information of col
table,So I used subquery as:
SELECT *
FROM offc.col
WHERE ( dept_id, year, marks ) IN (SELECT dept_id,
year,
Max(marks) marks
FROM offc.col
GROUP BY dept_id,
year
ORDER BY dept_id,
year);
But,I got error as:
ORA-00920: invalid relational operator
i searched this error at other pages also,but I found them as bracket misplace error.But in my case,I dont know what is happening here?
Upvotes: 1
Views: 886
Reputation: 50077
Perform an INNER JOIN with your subquery:
SELECT c.*
FROM offc.col c
INNER JOIN (SELECT dept_id,
year,
Max(marks) AS MAX_MARK
FROM offc.col
GROUP BY dept_id,
year) s
ON s.DEPT_ID = c.DEPT_ID AND
s.YEAR = c.YEAR AND
s.MAX_MARK = c.MARKS
ORDER BY c.DEPT_ID, c.YEAR
An INNER JOIN only returns rows where the join condition is satisfied so any rows in OFFC.COL which do not have the maximum value for MARKS for a particular DEPT_ID and YEAR will not be returned.
Upvotes: 0
Reputation: 35930
I would suggest to use dense_rank
analytical function as it can return two department if they have same marks in same year.(your current logic is same as this)
Row_number
will give you only one random record if two department have same marks in same year.
select *
from (
select
c.*,
dense_rank() over(partition by dept_id, year order by marks desc nulls last) as dr
from offc.col c
) x
where dr = 1
order by dept_id, year
Also, your query is correct, just remove order by from it.
SELECT *
FROM offc.col
WHERE ( dept_id, year, marks ) IN (SELECT dept_id,
year,
Max(marks) marks
FROM offc.col
GROUP BY dept_id,
year
-- ORDER BY dept_id,
-- year
);
Demo of error with order by
and working fine without order by
.
Cheers!!
Upvotes: 2
Reputation: 222702
Instead of aggregating, you can filter with a correlated subquery:
select c.*
from offc.col c
where marks = (
select max(marks)
from offc.col c1
where c1.dept_id = c.dept_id and c1.year = c.year
)
order by dept_id, year
An index on (dept_id, year, marks)
would speed up this query.
Another option is to use window function row_number()
:
select *
from (
select
c.*,
row_number() over(partition by dept_id, year order by marks desc) rn
from offc.col c
) x
where rn = 1
order by dept_id, year
If you do want to stick to aggregation, then you can join your subquery with the original table as follows:
select c.*
from offc.col c
inner join (
select dept_id, year, max(marks) marks
from offc.col
group by dept_id, year
) m
on m.dpt_id = c.dept_id
and m.year = c.year
and m.marks = m.marks
Upvotes: 1