Seleccione cuál tiene la fecha máxima o la última fecha

15

Aquí hay dos tablas.

PERSONAL DE LA ESCUELA

SCHOOL_CODE + STAFF_TYPE_NAME + LAST_UPDATE_DATE_TIME + PERSON_ID
=================================================================
ABE           Principal         24-JAN-13               111222
ABE           Principal         09-FEB-12               222111

Personas

PERSON_ID + NAME
=================
111222      ABC
222111      XYZ

Aquí está mi consulta de oráculo.

SELECT MAX(LAST_UPDATE_DATE_TIME) AS LAST_UPDATE, SCHOOL_CODE, PERSON_ID
FROM SCHOOL_STAFF
WHERE STAFF_TYPE_NAME='Principal'
GROUP BY SCHOOL_CODE, PERSON_ID
ORDER BY SCHOOL_CODE;

lo que da estos resultados

LAST_UPDATE SCHOOL_CODE PERSON_ID
===========+===========+=========
24-JAN-13   ABE         111222
09-FEB-12   ABE         222111

Quiero seleccionar el primero para la escuela que tiene la última fecha.

Gracias.

riz
fuente

Respuestas:

28

Su consulta actual no está dando el resultado deseado porque está utilizando una GROUP BYcláusula en la PERSON_IDcolumna que tiene un valor único para ambas entradas. Como resultado, devolverá ambas filas.

Hay algunas maneras en que puede resolver esto. Puede usar una subconsulta para aplicar la función de agregado para devolver el max(LAST_UPDATE_DATE_TIME)para cada SCHOOL_CODE:

select s1.LAST_UPDATE_DATE_TIME,
  s1.SCHOOL_CODE,
  s1.PERSON_ID
from SCHOOL_STAFF s1
inner join
(
  select max(LAST_UPDATE_DATE_TIME) LAST_UPDATE_DATE_TIME,
    SCHOOL_CODE
  from SCHOOL_STAFF
  group by SCHOOL_CODE
) s2
  on s1.SCHOOL_CODE = s2.SCHOOL_CODE
  and s1.LAST_UPDATE_DATE_TIME = s2.LAST_UPDATE_DATE_TIME;

Ver SQL Fiddle con Demo

O puede usar una función de ventana para devolver las filas de datos para cada escuela con la más reciente LAST_UPDATE_DATE_TIME:

select SCHOOL_CODE, PERSON_ID, LAST_UPDATE_DATE_TIME
from
(
  select SCHOOL_CODE, PERSON_ID, LAST_UPDATE_DATE_TIME,
    row_number() over(partition by SCHOOL_CODE 
                        order by LAST_UPDATE_DATE_TIME desc) seq
  from SCHOOL_STAFF
  where STAFF_TYPE_NAME='Principal'
) d
where seq = 1;

Ver SQL Fiddle con Demo

Esta consulta implementa row_number()que asigna un número único a cada fila de la partición SCHOOL_CODEy se coloca en orden descendente en función de LAST_UPDATE_DATE_TIME.

Como nota al margen, la función UNIR con agregado no es exactamente la misma que la row_number()versión. Si tiene dos filas con el mismo tiempo de evento, JOIN devolverá ambas filas, mientras row_number()que solo devolverá una. Si desea devolver ambos con una función de ventanas, considere usar la rank()función de ventanas en su lugar, ya que devolverá lazos:

select SCHOOL_CODE, PERSON_ID, LAST_UPDATE_DATE_TIME
from
(
  select SCHOOL_CODE, PERSON_ID, LAST_UPDATE_DATE_TIME,
    rank() over(partition by SCHOOL_CODE 
                        order by LAST_UPDATE_DATE_TIME desc) seq
  from SCHOOL_STAFF
  where STAFF_TYPE_NAME='Principal'
) d
where seq = 1;

Ver demo

Taryn
fuente
4

Me sorprende que nadie haya aprovechado las funciones de la ventana más allá de row_number ()

Aquí hay algunos datos para jugar:

CREATE TABLE SCHOOL_STAFF
(
LAST_UPDATE_DATE_TIME VARCHAR(20),
SCHOOL_CODE VARCHAR(20),
PERSON_ID VARCHAR(20),
STAFF_TYPE_NAME VARCHAR(20)
);
INSERT INTO SCHOOL_STAFF VALUES ('24-JAN-13', 'ABE', '111222', 'Principal');
INSERT INTO SCHOOL_STAFF VALUES ('09-FEB-12', 'ABE', '222111', 'Principal');

La cláusula OVER () crea una ventana para la cual definirá sus grupos agregados. En este caso, solo particiono en SHOOL_CODE, por lo que veremos el FIRST_VALUE, que vendrá de LAST_UPDATE_DATE_TIME, agrupado por SCHOOL_CODE, y en el orden de LAST_UPDATE_DATE_TIME por orden descendente. Este valor se aplicará a toda la columna para cada SCHOOL_CODE.

Es importante prestar mucha atención a su partición y orden en la cláusula over ().

SELECT DISTINCT
 FIRST_VALUE(LAST_UPDATE_DATE_TIME) OVER (PARTITION BY SCHOOL_CODE ORDER BY LAST_UPDATE_DATE_TIME DESC) AS LAST_UPDATE
,FIRST_VALUE(SCHOOL_CODE)           OVER (PARTITION BY SCHOOL_CODE ORDER BY LAST_UPDATE_DATE_TIME DESC) AS SCHOOL_CODE
,FIRST_VALUE(PERSON_ID)             OVER (PARTITION BY SCHOOL_CODE ORDER BY LAST_UPDATE_DATE_TIME DESC) AS PERSON_ID
FROM SCHOOL_STAFF
WHERE STAFF_TYPE_NAME = 'Principal'
ORDER BY SCHOOL_CODE

Devoluciones:

24-JAN-13   ABE 111222

Esto debería eliminar su necesidad de GROUP BY y Subconsultas en su mayor parte. Sin embargo, querrás asegurarte de incluir DISTINCT.

Andrés
fuente
1
select LAST_UPDATE_DATE_TIME as LAST_UPDATE,
  SCHOOL_CODE,
  PERSON_ID
from SCHOOL_STAFF
WHERE STAFF_TYPE_NAME='Principal'
AND LAST_UPDATE_DATE_TIME = (SELECT MAX(LAST_UPDATE_DATE_TIME)
                            FROM SCHOOL_STAFF s2
                            WHERE PERSON_ID = s2.PERSON_ID)
MouseInfa
fuente
1
En lugar de publicar solo el código, debe intentar explicar cómo esto responde la pregunta; y potencialmente lo que el OP estaba haciendo incorrectamente.
Max Vernon