Wybierz, która ma datę maksymalną lub najpóźniejszą

Oto dwie tabele.

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 

OSOBY

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

Oto moje zapytanie wyroczni.

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; 

co daje takie wyniki

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

Chcę wybrać pierwszą szkołę, która ma ostatnią datę.

Dziękuję.

Odpowiedź

Twoje obecne zapytanie nie daje oczekiwanych rezultatów, ponieważ używasz GROUP BY w kolumnie PERSON_ID, która ma unikalne wartości dla obu pozycji. W rezultacie zwrócisz oba wiersze.

Jest kilka sposobów rozwiązania tego problemu. Możesz użyć podzapytania, aby zastosować funkcję agregującą i zwrócić max(LAST_UPDATE_DATE_TIME) dla każdego 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; 

Zobacz SQL Fiddle with Demo

Możesz też użyć funkcja okienkowa , aby zwrócić wiersze danych dla każdej szkoły z najnowszymi 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; 

Zobacz SQL Fiddle with Demo

To zapytanie implementuje row_number() , który przypisuje niepowtarzalny numer do każdego wiersza w partycji SCHOOL_CODE i jest umieszczony w porządku malejącym na podstawie LAST_UPDATE_DATE_TIME.

Na marginesie, JOIN z funkcją agregującą nie jest dokładnie tym samym, co wersja row_number(). Jeśli masz dwa wiersze z tą samą godziną zdarzenia, JOIN zwróci oba wiersze, podczas gdy row_number() zwróci tylko jeden. Jeśli chcesz zwrócić oba za pomocą funkcji okienkującej, rozważ użycie funkcji okienkującej rank(), ponieważ zwróci ona powiązania:

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; 

Zobacz Demo

Komentarze

  • Dziękuję, uważam sprzężenie wewnętrzne do tabeli podzapytań (przykład 1 powyżej) jest najbardziej intuicyjne … i nie wymaga ', abym się nauczył, czym jest partycjonowanie według o. Oto spojrzenie na składnię podobną do przykładu 1: wybierz oT.dateField, oT.siteID, oT.field1, oT.field2, oT.field3, z originalTable jako oT wewnętrzne sprzężenie (wybierz max (dateField) jako newestDate, siteID z grupy originalTable według siteID) jako newTable w oT.siteID = newTable.site_ID i oT.dateField = newTable.newestDate order by oT.siteID asc To lepiej wyjaśnia, co ' dzieje się w podzapytaniu.

Odpowiedź

I „Jestem zaskoczony, że nikt nie wykorzystał funkcji okna poza row_number ()

Oto kilka danych do zabawy:

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

Klauzula OVER () tworzy okno, dla którego zdefiniujesz swoje grupy zagregowane. W tym przypadku partycjonuję tylko na SHOOL_CODE, więc zobaczymy FIRST_VALUE, który będzie pochodził z LAST_UPDATE_DATE_TIME, pogrupowany według SCHOOL_CODE i w kolejności LAST_UPDATE_DATE_TIME w porządku malejącym. Ta wartość zostanie zastosowana do całej kolumny dla każdego SCHOOL_CODE.

Ważne jest, aby zwrócić szczególną uwagę na partycjonowanie i porządkowanie w klauzuli 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 

Zwroty:

24-JAN-13 ABE 111222 

To powinno wyeliminować potrzebę GROUP BY i podzapytań przez większą część. Będziesz chciał jednak uwzględnić DISTINCT.

Komentarze

  • To miłe, ale czy istnieje sposób na uniknięcie powtarzania klauzuli over dla wszystkie kolumny?

Odpowiedź

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) 

Komentarze

  • Zamiast publikować tylko kod, powinieneś spróbować wyjaśnić, jak to odpowiada na pytanie; i potencjalnie to, co OP robił nieprawidłowo.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *