2011-03-15 8 views
5

Considere la tabla1 y la tabla2 con una relación de uno a varios (la tabla1 es la tabla maestra y la tabla2 es la tabla de detalles). Quiero obtener registros de la tabla 1, donde algún valor ('XXX') es el valor del registro más reciente en la tabla 2 de los registros de detalle correlacionados con la tabla1. Lo que quiero hacer es lo siguiente:Problema de subconsulta correlacionada anidada de Oracle

select t1.pk_id 
    from table1 t1 
where 'XXX' = (select a_col 
        from ( select a_col 
          from table2 t2 
          where t2.fk_id = t1.pk_id 
         order by t2.date_col desc) 
       where rownum = 1) 

Pero, debido a que la referencia a la tabla 1 (T1) en la subconsulta correlacionada es de dos niveles de profundidad, que aparece con un error de Oracle (no válido t1 id). Necesito poder reescribir esto, pero la única advertencia es que solo se puede cambiar la cláusula where (es decir, la selección inicial y la opción deben permanecer sin cambios). Se puede hacer?

Respuesta

6

He aquí un enfoque analítico diferente:

select t1.pk_id 
    from table1 t1 
where 'XXX' = (select distinct first_value(t2.a_col) 
            over (order by t2.date_col desc) 
        from table2 t2 
        where t2.fk_id = t1.pk_id) 

Y aquí está la misma idea utilizando una función de clasificación:

select t1.pk_id 
    from table1 t1 
where 'XXX' = (select max(t2.a_col) keep 
          (dense_rank first order by t2.date_col desc) 
        from table2 t2 
        where t2.fk_id = t1.pk_id) 
+0

Voy a intentar esto. Lo comprobaré más tarde. Gracias. – GriffeyDog

+0

Gracias Dave, cada ejemplo funciona muy bien. Estaba pensando que esto podría hacerse con funciones analíticas, pero no estaba muy seguro de cómo escribirlo. – GriffeyDog

+0

¿Qué sucede si quiero el segundo, tercer y siguiente resultado con esa cláusula order by? ¿Es posible usando este enfoque? – Sawd

-1

Prueba esto:

select t1.pk_id 
from table1 t1 
where 'XXX' = 
(select a_col 
from table2 t2       
where t2.fk_id = t1.pk_id       
and t2.date_col = 
    (select max(t3.date_col) 
    from table2 t3 
    where t3.fk_id = t2.fk_id) 
) 
+0

Solo si date_col es único, lo que parece poco probable. – Mark

-1

hace esto lo que está buscando?

select t1.pk_id 
    from table1 t1 
where 'XXX' = ( select a_col 
        from table2 t2 
        where t2.fk_id = t1.pk_id 
        t2.date_col = (select max(date_col) from table2 where fk_id = t1.pk_id) 
       ) 
+0

Solo si date_col es único, lo que parece poco probable. – Mark

3

se podía utilizar análisis aquí: unirse a tabla1 a tabla2, tomar el registro más reciente tabla2 para cada elemento en la tabla 1 y verificar que este elemento más reciente tiene un valor de 'XXX':

SELECT * 
    FROM (SELECT t1.*, 
       t2.a_col, 
       row_number() over (PARTITION BY t1.pk 
            ORDER BY t2.date_col DESC) rnk 
      FROM table1 t1 
      JOIN table2 t2 ON t2.fk_id = t1.pk_id) 
WHERE rnk = 1 
    AND a_col = 'XXX' 

actualización: Sin modificar el nivel superior SELECT, se podría escribir una consulta como esta:

SELECT t1.pk_id 
    FROM table1 t1 
WHERE 'XXX' = 
     (SELECT a_col 
      FROM (SELECT a_col, 
         t2_in.fk_id, 
         row_number() over(PARTITION BY t2_in.fk_id 
             ORDER BY t2_in.date_col DESC) rnk 
        FROM table2 t2_in) t2 
     WHERE rnk = 1 
      AND t2.fk_id = t1.pk_id) 

Básicamente sólo se unen (SEMI-JOIN) las filas de tabla2 que son el más reciente para cada fk_id

+0

No deseo cambiar las cláusulas de selección o de nivel superior. – GriffeyDog

+0

@GriffeyDog: esto parece bastante arbitrario: p –

+0

Es debido a cómo nuestra aplicación está construyendo la consulta. El select y from son más o menos constantes, y luego where incluye varios filtros que aplicamos a los datos. – GriffeyDog

Cuestiones relacionadas