2009-04-29 21 views
6

Estoy tratando de averiguar la cantidad promedio de veces que aparece un valor en una columna, agruparlo basado en otra columna y luego realizar un cálculo en él.SQL AVG (COUNT (*))?

tengo 3 mesas un poco como esta

DVD 

ID | NAME 
1 | 1  
2 | 1  
3 | 2  
4 | 3 

COPY 

ID | DVDID 
1 | 1 
2 | 1 
3 | 2 
4 | 3 
5 | 1 

LOAN 

ID | DVDID | COPYID 
1 | 1  | 1 
2 | 1  | 2 
3 | 2  | 3  
4 | 3  | 4 
5 | 1  | 5 
6 | 1  | 5 
7 | 1  | 5 
8 | 1  | 2 

etc

Básicamente, estoy tratando de encontrar todos los identificadores de copia que aparecen en la tabla de préstamo de veces menor que el número medio de veces para todas las copias de ese DVD.

En el ejemplo anterior, copie 5 de dvd 1 3 veces, copie 2 dos veces y copie 1 una vez para que el promedio de ese DVD sea 2. Quiero enumerar todas las copias de ese (y cada uno) dvd que aparecen menos que ese número en la tabla de préstamos.

Espero que tenga un poco más de sentido ...

Gracias

+0

Entonces, en su ejemplo, ¿qué conjunto de datos de resultados debe devolverse? ¿Debería emitir 2 para DVDID = 1 y 1 para los otros dos? –

+1

... porque decir 'la cantidad promedio de veces que aparece un valor en una columna' no tiene ningún sentido. El número de veces que aparece es el número de veces que aparece; no puedes promediar un valor –

+0

Lo siento, ¡estoy medio dormido! Quise decir que quiero encontrar el número promedio de veces que aparecen copias de cada DVD en la tabla de Préstamo –

Respuesta

2

Esto debería funcionar en Oracle:

create view dvd_count_view 
select dvdid, count(1) as howmanytimes 
    from loans 
group by dvdid; 

select avg(howmanytimes) from dvd_count_view; 
2

No comprobado ...

with 
loan_copy_total as 
(
    select dvdid, copyid, count(*) as cnt 
    from loan 
    group by dvdid, copyid 
), 
loan_copy_avg as 
(
    select dvdid, avg(cnt) as copy_avg 
    from loan_copy_total 
    group by dvdid 
) 

select lct.*, lca.copy_avg 
from loan_copy_avg lca 
inner join loan_copy_total lct on lca.dvdid = lct.dvdid 
    and lct.cnt <= lca.copy_avg; 
2

similares a la solución de dotjoe, pero usando una función analítica para evitar la unión extra. Puede ser más o menos eficiente.

with 
loan_copy_total as 
(
    select dvdid, copyid, count(*) as cnt 
    from loan 
    group by dvdid, copyid 
), 
loan_copy_avg as 
(
    select dvdid, copyid, cnt, avg(cnt) over (partition by dvdid) as copy_avg 
    from loan_copy_total 
) 

select * 
from loan_copy_avg lca 
where cnt <= copy_avg; 
+0

He estado viendo esta sintaxis 'con' últimamente. ¿Es este SQL estándar o está en Oracle? –

+0

Es parte del estándar ANSI SQL –