2011-02-25 9 views
10

Estoy intentando ejecutar una subconsulta en Oracle SQL y no me permitirá ordenar las columnas de la subconsulta. Ordenar la subconsulta es importante ya que Oracle parece elegir a voluntad cuál de las columnas devueltas para volver a la consulta principal.Oracle SQL orden por en problemas de subconsulta!

select ps.id, ps.created_date, pst.last_updated, pst.from_state, pst.to_state, 
     (select last_updated from mwcrm.process_state_transition subpst 
      where subpst.last_updated > pst.last_updated 
      and subpst.process_state = ps.id 
      and rownum = 1) as next_response 
     from mwcrm.process_state ps, mwcrm.process_state_transition pst 
     where ps.created_date > sysdate - 1/24 
     and ps.id=pst.process_state 
     order by ps.id asc 

realmente debe ser:

select ps.id, ps.created_date, pst.last_updated, pst.from_state, pst.to_state, 
     (select last_updated from mwcrm.process_state_transition subpst 
      where subpst.last_updated > pst.last_updated 
      and subpst.process_state = ps.id 
      and rownum = 1 
      order by subpst.last_updated asc) as next_response 
     from mwcrm.process_state ps, mwcrm.process_state_transition pst 
     where ps.created_date > sysdate - 1/24 
     and ps.id=pst.process_state 
     order by ps.id asc 

Respuesta

19

realidad "ordenamiento" sólo tiene sentido en la consulta externa - si usted ordena en una subconsulta, se permite la consulta externa para codificar los resultados a voluntad, por lo que el orden de la subconsulta no hace prácticamente nada.

Parece que solo desea obtener el mínimo last_updated que sea mayor que pst.last_updated; es más fácil cuando lo ve como el mínimo (un agregado), en lugar de una primera fila (lo que ocasiona otros problemas) , ¿qué pasa si hay dos filas vinculadas para next_response?)

Dale una oportunidad. Una advertencia justa, han pasado unos años desde que tuve Oracle en frente de mí, y no estoy acostumbrado a la sintaxis de subconsulta en columna; si esto explota, haré una versión con eso en la cláusula from.

select 
    ps.id, ps.created_date, pst.last_updated, pst.from_state, pst.to_state, 
    ( select min(last_updated) 
     from mwcrm.process_state_transition subpst 
     where subpst.last_updated > pst.last_updated 
      and subpst.process_state = ps.id) as next_response 
from <the rest> 
+3

+1 para usar un agregado en lugar de ROWNUM. ROWNUM es el doble de pensamiento sin relación. –

+2

¿Dónde está mi +1 por usar MIN? -cry- – MatBailie

8

que he experimentado esto mismo y tiene que usar ROW_NUMBER(), y un nivel adicional de sub consulta, en lugar de rownum ...

Sólo muestra la nueva sub consulta, algo así como ...

(
    SELECT 
    last_updated 
    FROM 
    (
    select 
     last_updated, 
     ROW_NUMBER() OVER (ORDER BY last_updated ASC) row_id 
    from 
     mwcrm.process_state_transition subpst 
    where 
     subpst.last_updated > pst.last_updated 
     and subpst.process_state = ps.id 
) 
    as ordered_results 
    WHERE 
    row_id = 1 
) 
    as next_response 


Una alternativa sería utilizar MIN lugar ...

(
    select 
    MIN(last_updated) 
    from 
    mwcrm.process_state_transition subpst 
    where 
    subpst.last_updated > pst.last_updated 
    and subpst.process_state = ps.id 
) 
    as next_response 
+0

más 1 para usar MIN :) (4 años en el futuro) :) – Alex

13

Tanto dcw como Dems han proporcionado consultas alternativas apropiadas. Solo quería arrojar una explicación de por qué su consulta no se comporta de la manera que esperaba.

Si tiene una consulta que incluye un ROWNUM y un ORDER BY, Oracle aplica primero el ROWNUM y luego el ORDER BY. Por lo que la consulta

SELECT * 
    FROM emp 
WHERE rownum <= 5 
ORDER BY empno 

obtiene una arbitrarias 5 filas de la tabla y el tipo EMP ellos-- es casi seguro que lo que se pretendía. Si desea obtener las "primeras N" filas utilizando ROWNUM, deberá anidar la consulta. Esta consulta

SELECT * 
    FROM (SELECT * 
      FROM emp 
     ORDER BY empno) 
WHERE rownum <= 5 

ordena las filas de la tabla EMP y devuelve el primer 5.

+0

¡Gracias por esta excelente respuesta! Casi fui con la primera consulta sin darme cuenta de mi error hasta que vi su publicación. Hice algunas pruebas y tiene razón, la consulta interna (en la segunda consulta) devuelve el orden de rownum arbitrario cuando se aplica ORDER BY, pero los rownums de consulta externa están en orden ascendente (me permite obtener la primera fila usando rownum = 1; belleza sobre funciones agregadas como MAX y MIN). =) – ADTC

0

La respuesta confirmada es simplemente erróneo. Considere una subconsulta que genere un número de índice de fila único. Por ejemplo ROWNUM en Oracle.

Necesita la subconsulta para crear el número de registro exclusivo para la búsqueda (ver a continuación).

consideremos el siguiente ejemplo consulta:

SELECT T0.*, T1.* FROM T0 LEFT JOIN T1 ON T0.Id = T1.Id 
JOIN 
(
SELECT DISTINCT T0.*, ROWNUM FROM T0 LEFT JOIN T1 ON T0.Id = T1.Id 
WHERE (filter...) 
) 
WHERE (filter...) AND (ROWNUM > 10 AND ROWNUM < 20) 
ORDER BY T1.Name DESC 

La consulta interna es la misma consulta exacta, pero DISTINCT en T0. No puede poner el ROWNUM en la consulta externa ya que el LEFT JOIN (s) podría generar muchos más resultados.

Si pudiera solicitar la consulta interna (T1.Name DESC), la ROWNUM generada en la consulta interna coincidiría. Dado que no puede usar un ORDER B Y en la subconsulta, los números no coincidirán y serán inútiles.

Gracias a dios por ROW_NUMBER OVER (ORDER BY ...) que soluciona este problema. Aunque no es compatible con todos los motores DB.

Uno de los dos métodos, LIMIT (no requiere ORDER) y ROW_NUMBER() OVER cubrirán la mayoría de los motores DB. Pero aún así, si no tiene una de estas opciones, por ejemplo, el ROWNUM es su única opción, ¡entonces es obligatorio tener ORDER BY en la subconsulta!

Cuestiones relacionadas