sql >> Base de Datos >  >> RDS >> PostgreSQL

Encuentre películas con el mayor número de premios en cierto año:duplicación de código

Bueno, puedes usar expresión de tabla común para evitar la duplicación de código:

with cte_s as (
   select id_movie, count(id_movie) as awards
   from Award natural join awardwinner 
   where award_year = 2012
   group by id_movie
)
select
    sub.id_movie, sub.awards
from cte_s as sub
where sub.awards = (select max(sub2.awards) from cte_s as sub2)

o puede hacer algo como esto con función de ventana (no probado, pero creo que PostgreSQL lo permite):

with cte_s as (
    select
        id_movie,
        count(id_movie) as awards,
        max(count(id_movie)) over() as max_awards
    from Award natural join awardwinner 
    where award_year = 2012
    group by id_movie
)
select id_movie
from cte_s
where max_awards = awards

Otra forma de hacer esto podría ser usar rank() función (no probada, puede ser que tenga que usar dos cte en lugar de uno):

with cte_s as (
    select
        id_movie,
        count(id_movie) as awards,
        rank() over(order by count(id_movie) desc) as rnk
    from Award natural join awardwinner 
    where award_year = 2012
    group by id_movie
)
select id_movie
from cte_s
where rnk = 1

actualizar Cuando creé esta respuesta, mi objetivo principal era mostrar cómo usar cte para evitar la duplicación de código. En general, es mejor evitar usar cte más de una vez en la consulta si es posible:la primera consulta usa 2 tablas de escaneo (o búsqueda de índice) y la segunda y la tercera usan solo una, por lo que debo especificar que es mejor ir con estas consultas. De todos modos, @Erwin hizo estas pruebas en su respuesta. Solo para agregar a sus grandes puntos principales:

  • También desaconsejo la natural join debido a la naturaleza propensa a errores de esto. En realidad, mi RDBMS principal es SQL Server, que no lo admite, por lo que estoy más acostumbrado a outer/inner join explícita. .
  • Es un buen hábito usar siempre alias en sus consultas, para que pueda evitar resultados extraños .
  • Esto podría ser algo totalmente subjetivo, pero por lo general, si estoy usando una tabla solo para filtrar las filas de la tabla principal de la consulta (como en esta consulta, solo queremos obtener awards para el año 2012 y solo filtre las filas de awardwinner ), prefiero no usar join , pero el uso exists o in en cambio, me parece más lógico.
Entonces, la consulta final podría ser:
with cte_s as (
    select
        aw.id_movie,
        count(*) as awards,
        rank() over(order by count(*) desc) as rnk
    from awardwinner as aw
    where
        exists (
            select *
            from award as a
            where a.id_award = aw.id_award and a.award_year = 2012
        )
    group by aw.id_movie
)
select id_movie
from cte_s
where rnk = 1