Vælg den, der har maks. Dato eller seneste dato

Her er to tabeller.

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 

PERSONER

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

Her er min oracle-forespørgsel.

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; 

hvilket giver disse resultater

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

Jeg vil vælge den første til skolen, der har den seneste dato.

Tak.

Svar

Din aktuelle forespørgsel giver ikke det ønskede resultat, fordi du bruger en GROUP BY klausul i kolonnen PERSON_ID, som har en unik værdi for begge poster. Som et resultat vil du returnere begge rækker.

Der er et par måder, du kan løse dette på. Du kan bruge en underforespørgsel til at anvende den samlede funktion til at returnere max(LAST_UPDATE_DATE_TIME) for hver 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; 

Se SQL-spil med demo

Eller du kan bruge en vinduesfunktion for at returnere datarækkerne for hver skole med den seneste 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; 

Se SQL-spil med demo

Denne forespørgsel implementerer row_number() som tildeler et unikt nummer til hver række i partitionen af SCHOOL_CODE og placeres i en faldende rækkefølge baseret på LAST_UPDATE_DATE_TIME.

Som en sidebemærkning er JOIN med samlet funktion ikke nøjagtigt den samme som row_number() versionen. Hvis du har to rækker med samme begivenhedstid, returnerer JOIN begge rækker, mens row_number() kun returnerer en. Hvis du vil returnere begge med en vinduesfunktion, skal du overveje at bruge rank() vinduesfunktionen i stedet, da den returnerer bånd:

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; 

Se Demo

Kommentarer

  • Tak, jeg finder den indre sammenføjning til en underforespørgselstabel (eksempel 1 ovenfor) for at være den mest intuitive .. og kræver ikke ' mig at lære, hvad partition af alt er om. Her er et kig på en lignende syntaks som eksempel 1: vælg oT.dateField, oT.siteID, oT.field1, oT.field2, oT.field3, fra originalTable som oT indre sammenføjning (vælg max (dateField) som nyeste dato, siteID fra originalTabel gruppe efter siteID) som newTable på oT.siteID = newTable.site_ID og oT.dateField = newTable.newestDate rækkefølge efter oT.siteID asc For mig forklarer det bedre ' sker i underforespørgslen.

Svar

I “Jeg er overrasket over, at ingen har udnyttet vinduesfunktioner ud over række_nummer ()

Her er nogle data at lege med:

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 () klausul opretter et vindue, som du vil definere dine samlede grupper til. I dette tilfælde partitionerer jeg kun på SHOOL_CODE, så vi vil se FIRST_VALUE, som kommer fra LAST_UPDATE_DATE_TIME, grupperet efter SCHOOL_CODE og i rækkefølgen LAST_UPDATE_DATE_TIME efter faldende rækkefølge. Denne værdi vil blive anvendt på hele kolonnen for hver SCHOOL_CODE.

Det er vigtigt at være meget opmærksom på din partitionering og bestilling i over () -klausulen.

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 

Returnerer:

24-JAN-13 ABE 111222 

Dette bør eliminere dit behov for GROUP BY og underforespørgsler for det meste. Du skal dog sørge for at inkludere DISTINCT.

Kommentarer

  • Dette er rart, men er der en måde at undgå at gentage overklausulen for alle kolonner?

Svar

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) 

Kommentarer

  • I stedet for at sende bare kode, skal du prøve at forklare, hvordan dette besvarer spørgsmålet; og potentielt hvad OP gjorde forkert.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *