Виберіть, яка має максимальну або останню дату


15

Ось дві таблиці.

SCHOOL_STAFF

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

ОСОБИ

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

Ось мій запит на оракул.

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;

що дає такі результати

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

Я хочу вибрати першу для школи, яка має останню дату.

Спасибі.

Відповіді:


28

Ваш поточний запит не дає бажаного результату, оскільки ви використовуєте GROUP BYпункт про PERSON_IDстовпчик, який має унікальне значення для обох записів. В результаті ви повернете обидва ряди.

Є кілька способів вирішити це. Ви можете використовувати підзапит, щоб застосувати функцію сукупності для повернення max(LAST_UPDATE_DATE_TIME)для кожного 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;

Див. SQL Fiddle with Demo

Або ви можете використовувати функцію вікон, щоб повернути рядки даних для кожної школи з останніми 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;

Див. SQL Fiddle with Demo

Цей запит реалізує, row_number()який присвоює унікальний номер кожному рядку в розділі SCHOOL_CODEта розміщується у низхідному порядку на основі LAST_UPDATE_DATE_TIME.

Як бічне зауваження, JOIN з агрегатною функцією не точно збігається з row_number()версією. Якщо у вас є два ряди з однаковим часом події, ПРИЄДНУЙСЯ поверне обидва ряди, тоді як row_number()лише один повернеться. Якщо ви хочете повернути обидва за допомогою функції вікна, тоді rank()замість цього скористайтеся функцією вікна, оскільки вона поверне зв'язки:

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;

Див. Демо


4

Я здивований, що ніхто не скористався функціями вікна поза row_number ()

Ось деякі дані, з якими можна грати:

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');

Пункт OVER () створює вікно, для якого ви визначите свої сукупні групи. У цьому випадку я розбиваю лише розділ на SHOOL_CODE, тому ми побачимо FIRST_VALUE, який надходитиме від LAST_UPDATE_DATE_TIME, згрупований за SCHOOL_CODE, та в порядку LAST_UPDATE_DATE_TIME у порядку зменшення. Це значення буде застосовано до всього стовпця для кожного SCHOOL_CODE.

Важливо приділити пильну увагу своєму поділу та впорядкуванню в пункті 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

Повернення:

24-JAN-13   ABE 111222

Це повинно усунути вашу потребу в GROUP BY та Subqueries здебільшого. Ви хочете обов’язково включити DISTINCT.


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)

1
Замість того, щоб публікувати лише код, слід спробувати пояснити, як це відповідає на питання; і потенційно те, що ОП робила неправильно.
Макс Вернон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.