2008-09-25 10 views
7

¿Cómo podría obtener N resultados para varios grupos en una consulta de Oracle?Obtenga los mejores resultados para cada grupo (en Oracle)

Por ejemplo, dada la siguiente tabla:

|--------+------------+------------| 
| emp_id | name  | occupation | 
|--------+------------+------------| 
|  1 | John Smith | Accountant | 
|  2 | Jane Doe | Engineer | 
|  3 | Jack Black | Funnyman | 
|--------+------------+------------| 

hay muchas más filas con más ocupaciones. Me gustaría obtener tres empleados (digamos) de cada ocupación.

¿Hay alguna manera de hacerlo sin utilizar una subconsulta?

Respuesta

11

Esto produce lo que desea, y no utiliza características de SQL específicas del proveedor como TOP N o RANK().

SELECT e.name, e.occupation 
FROM emp AS e 
    LEFT OUTER JOIN emp AS e2 
    ON (e.occupation = e2.occupation AND e.emp_id <= e2.emp_id) 
GROUP BY e.emp_id 
HAVING COUNT(*) <= 3 
ORDER BY e.occupation; 

En este ejemplo, proporciona los tres empleados con los valores emp_id más bajos por ocupación. Puede cambiar el atributo utilizado en la comparación de desigualdad, para que le dé a los mejores empleados por su nombre o lo que sea.

+3

Creo que esto fallará en la cláusula GROUP BY. No hay funciones agregadas en su lista de selección. – jop

+1

Hice esta consulta antes de publicarla. SQL no requiere funciones agregadas para usar GROUP BY. –

2

No estoy seguro de que esto sea muy eficiente, ¿pero quizás un lugar de partida?

select * 
from people p1 
    join people p2 
     on p1.occupation = p2.occupation 
    join people p3 
     on p1.occupation = p3.occupation 
     and p2.occupation = p3.occupation 
where p1.emp_id != p2.emp_id 
    and p1.emp_id != p3.emp_id 

Esto debería darle filas que contengan 3 empleados distintos, todos en la misma ocupación. Desafortunadamente, le dará TODAS las combinaciones de esos.

¿Alguien puede reducir esto por favor?

28

no tengo una instancia de Oracle útil en este momento, así que no he probado esto:

select * 
from (select emp_id, name, occupation, 
     rank() over (partition by occupation order by emp_id) rank 
     from employee) 
where rank <= 3 

Aquí hay un enlace sobre cómo funciona rango: http://www.psoug.org/reference/rank.html

+2

Didnt que especifica sin una subconsulta ...? – AviD

+1

Sí, pero es posible que haya querido decir "sin utilizar una subconsulta que selecciona de la misma tabla". Esta solución usa una subconsulta pero solo accede a la tabla una vez. –

2

probado esto en SQL Server (y que utiliza subconsulta)

select emp_id, name, occupation 
from employees t1 
where emp_id IN (select top 3 emp_id from employees t2 where t2.occupation = t1.occupation) 

acaba de hacer una orden en la subconsulta para satisfacer sus necesidades

2

Añadir ROWNUM al grado:

select * from 
     (select emp_id, name, occupation,rank() over (partition by occupation order by emp_id,RowNum) rank 
         from employee) 
     where rank <= 3 
Cuestiones relacionadas