2012-04-27 34 views
9

Mi mesa:Oracle SQL - Funciones analíticas OVER a group?

ID NUM VAL 
1 1  Hello 
1 2  Goodbye 
2 2  Hey 
2 4  What's up? 
3 5  See you 

Si quiero devolver el número máximo para cada ID, que es muy bonito y limpio:

SELECT MAX(NUM) FROM table GROUP BY (ID) 

Pero lo que si quiero agarrar el valor asociado con el máximo de cada número para cada ID?

Por qué no puedo hacer:

SELECT MAX(NUM) OVER (ORDER BY NUM) FROM table GROUP BY (ID) 

¿Por qué es un error? Me gustaría tener esta selección agrupada por ID, en lugar de particionar por separado para cada ventana ...

EDITAR: El error es "no es una expresión GROUP BY".

+1

no podemos ver su mensaje de error desde aquí. – RBarryYoung

+0

¿Puede mostrar el resultado que espera, la descripción no tiene sentido para mí ... 'Quiero tomar el valor asociado con el máximo de cada número para cada ID'. Tampoco estoy seguro de qué diferencia haría un ORDER BY en una función MAX() ... – MatBailie

+0

No es una respuesta exacta a la pregunta, pero una buena introducción sobre el oráculo Las funciones analíticas se pueden encontrar en [orafaq] (http: // www.orafaq.com/node/55). La publicación ayuda a comprender los conceptos con ejemplos simples. –

Respuesta

13

Probablemente se podría utilizar la función MAX() KEEP(DENSE_RANK LAST...):

with sample_data as (
    select 1 id, 1 num, 'Hello' val from dual union all 
    select 1 id, 2 num, 'Goodbye' val from dual union all 
    select 2 id, 2 num, 'Hey' val from dual union all 
    select 2 id, 4 num, 'What''s up?' val from dual union all 
    select 3 id, 5 num, 'See you' val from dual) 
select id, max(num), max(val) keep (dense_rank last order by num) 
from sample_data 
group by id; 
+1

+1 Guau, esta respuesta es buena. ¿Sabía que hay funcionalidad de KEEP en la función de ventana, o tal vez es propiedad de Oracle, sin embargo, esta es una solución elegante. Esta respuesta funciona en la mayoría de las bases de datos a través de http://stackoverflow.com/a/10359164 Oracle: http://www.sqlfiddle.com/#!4/a9a07/19 Sql Server: http://www.sqlfiddle.com/ #! 3/a9a07/1 Postgresql: http://www.sqlfiddle.com/#!1/a9a07/6 –

+0

Me encanta cómo constantemente encuentro preguntas sobre Oracle con solo una consulta y sin explicación sobre qué demonios está haciendo y cómo funciona. Muy útil para aplicar la solución a otras situaciones. – jpmc26

3

Si usted está buscando para obtener las filas que contienen los valores de MAX(num) GROUP BY id, esto tiende a ser un patrón común ...

WITH 
    sequenced_data 
AS 
(
    SELECT 
    ROW_NUMBER() OVER (PARTITION BY id ORDER BY num DESC) AS sequence_id, 
    * 
    FROM 
    yourTable 
) 
SELECT 
    * 
FROM 
    sequenced_data 
WHERE 
    sequence_id = 1 


EDITAR

No sé si TeraData permitirá esto, pero la lógica parece tener sentido ...

SELECT 
    * 
FROM 
    yourTable 
WHERE 
    num = MAX(num) OVER (PARTITION BY id) 

O tal vez ...

SELECT 
    * 
FROM 
(
    SELECT 
    *, 
    MAX(num) OVER (PARTITION BY id) AS max_num_by_id 
    FROM 
    yourTable 
) 
    AS sub_query 
WHERE 
    num = max_num_by_id 

Esto es ligeramente diferente de mi respuesta anterior; si se vinculan varios registros con el mismo MAX(num), se devolverán todos, la otra respuesta solo devolverá uno.


EDITAR

En su SQL propuesto el error se relaciona con el hecho de que la cláusula OVER() contiene un campo no en su GROUP BY. Es como tratar de hacer esto ...

SELECT id, num FROM yourTable GROUP BY id 

num no es válido, porque no puede haber varios valores en ese campo para cada fila devuelta (con las filas devueltas definidas por GROUP BY id).

De la misma manera, no puede poner num dentro de la cláusula OVER().

SELECT 

    id, 

    MAX(num),    <-- Valid as it is an aggregate 

    MAX(num)     <-- still valid 
    OVER(PARTITION BY id), <-- Also valid, as id is in the GROUP BY 

    MAX(num)     <-- still valid 
    OVER(PARTITION BY num) <-- Not valid, as num is not in the GROUP BY 

FROM 
    yourTable 
GROUP BY 
    id 


Ver esta pregunta para cuando no se puede especificar algo en la cláusula OVER() y una respuesta que muestra cuándo (creo) puede: over-partition-by-question

+1

un viaje rápido a [http://sqlfiddle.com] (http://www.sqlfiddle.com/#!4/a9a07/23) podría verificar que esto no funciona: 'select id, val from yourTable where num = max (num) over (partición por id) '. Sin embargo, sería bueno si funciona, muy conciso –

4

Al utilizar función de ventana, no necesita usar GROUP BY nunca más, esto sería suficiente:

select id, 
    max(num) over(partition by id) 
from x 

En realidad, usted puede obtener el resultado sin necesidad de utilizar la función de ventanas:

select * 
from x 
where (id,num) in 
    (
    select id, max(num) 
    from x 
    group by id 
) 

Salida:

ID NUM VAL 
1 2 Goodbye 
2 4 What's up 
3 5 SEE YOU 

http://www.sqlfiddle.com/#!4/a9a07/7


Si desea utilizar la función de ventanas, que podría hacer esto:

select id, val, 
    case when num = max(num) over(partition by id) then 
     1 
    else 
     0 
    end as to_select 
from x 
where to_select = 1 

O esto:

select id, val 
from x 
where num = max(num) over(partition by id) 

Pero ya que no está permitido hacer aquellos, que tienen que hacer esto:

with list as 
(
    select id, val, 
    case when num = max(num) over(partition by id) then 
     1 
    else 
     0 
    end as to_select 
    from x 
) 
select * 
from list 
where to_select = 1 

http://www.sqlfiddle.com/#!4/a9a07/19

+0

¿Qué significa el 'ORDER BY num'? 'MAX()' de '1,2,3' es lo mismo que' MAX() 'de' 2,3,1' ... Para 'MAX()', seguramente solo '' PARTITION BY' tiene sentido? – MatBailie

+1

sí, es cierto, solo PARTITION BY tiene sentido en MAX. el primer código (MAX OVER ORDER BY) en mi respuesta fue copiado y copiado rápidamente de la pregunta del OP. ORDER BY en la función de ventana solo tiene sentido en el total acumulado, p. SUM –

+0

Bueno, ROW_NUMBER(), RANK(), etc, * (dado que devuelven valores diferentes en función de la posición/orden) * pero no MIN(), MAX(), SUM()? – MatBailie

Cuestiones relacionadas