1
create table tab1(sno int, name varchar(30), age int);

insert into tab1 values(1, 'abc1', 22);
insert into tab1 values(2, 'abc2', 23);
insert into tab1 values(3, 'xyz', 28);
insert into tab1 values(4, 'abc3', 26);
insert into tab1 values(5, 'abc4', 25);

select sno, name, age, rank() over (order by sno) as ranking from tab1 where
ranking = trunc((select count(*)/2 from tab1)) + 1; //This query is giving error

Error is ORA-00904: "RANKING": invalid identifier

Andrew
  • 4,953
  • 15
  • 40
  • 58
Alvin3001
  • 109
  • 1
  • 9

2 Answers2

5

You are trying to filter the results of your select based on value that is calculated after all filtering is done. You need to change it to something like this:

select * from (
  select sno, name, age, rank() over (order by sno) as ranking from tab1 
) where ranking = trunc((select count(*)/2 from tab1)) + 1;
Emil Moise
  • 373
  • 1
  • 8
2

Your problem is thank you define an alias in the select and then you want to filter by it. You need to use either a CTE or subquery:

with cte as (
      select sno, name, age, rank() over (order by sno) as ranking
      from tab1
     )
select cte.*
from cte
where cte.ranking = trunc((select count(*)/2 from tab1)) + 1; 

You seem to want to calculate the median value. I would definitely not recommend rank() for this purpose, because of the way that it treats ties. A better alternative is row_number(), so this is pretty close to getting the median. And, you don't need the subquery:

with cte as (
      select sno, name, age, row_number() over (order by sno) as ranking,
             count(*) over () as cnt
      from tab1
     )
select cte.*
from cte
where 2*cte.ranking in (cnt, cnt + 1)

This works well enough for both even and odd numbers of rows.

You might also be interested in the MEDIAN(), PERCENTILE_DISC(), and PERCENTILE_CONT() functions.

Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786