Velg hvilken som har maks dato eller siste 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 orakelspørringen.

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; 

som gir disse resultatene

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

Jeg vil velge den første for skolen som har siste dato.

Takk.

Svar

Det nåværende spørsmålet ditt gir ikke det ønskede resultatet fordi du bruker en GROUP BY ledd i PERSON_ID -kolonnen som har en unik verdi for begge oppføringene. Som et resultat vil du returnere begge radene.

Det er noen måter du kan løse dette på. Du kan bruke et underspørring for å bruke den samlede funksjonen for å 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-fele med demo

Eller du kan bruke en vindusfunksjon for å returnere dataradene for hver skole med den siste 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-fikle med demo

Dette spørsmålet implementerer row_number() som tildeler et unikt nummer til hver rad i partisjonen til SCHOOL_CODE og plasseres i en synkende rekkefølge basert på LAST_UPDATE_DATE_TIME.

Som en sidemerknad er JOIN med samlet funksjon ikke akkurat den samme som row_number() -versjonen. Hvis du har to rader med samme hendelsestid, returnerer JOIN begge radene, mens row_number() bare returnerer en. Hvis du vil returnere begge med en vindusfunksjon, bør du vurdere å bruke rank() vindusfunksjonen 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

  • Takk, jeg finner ut den indre sammenføyningen til en undersøketabell (eksempel 1 ovenfor) for å være den mest intuitive .. og krever ikke ' meg å lære hva partisjon av er alt Om. Her er en titt på en lignende syntaks som eksempel 1: velg oT.dateField, oT.siteID, oT.field1, oT.field2, oT.field3, fra originalTable som oT indre sammenføyning (velg max (dateField) som nyeste dato, side-ID fra originalTabellgruppe etter side-ID) som nyTabell på oT.siteID = newTable.site_ID og oT.dateField = newTable.newestDate rekkefølge etter oT.siteID asc For meg forklarer det bedre hva ' skjer i underforespørselen.

Svar

I «Jeg er overrasket over at ingen har utnyttet vindusfunksjoner utover radnummer ()

Her er noen data å spille 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 oppretter et vindu som du vil definere dine samlede grupper for. I dette tilfellet deler jeg bare på SHOOL_CODE, så vi vil se FIRST_VALUE, som kommer fra LAST_UPDATE_DATE_TIME, gruppert etter SCHOOL_CODE, og i rekkefølgen LAST_UPDATE_DATE_TIME etter synkende rekkefølge. Denne verdien vil bli brukt på hele kolonnen for hver SCHOOL_CODE.

Det er viktig å være nøye med partisjonering 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 ditt behov for GROUP BY og underspørsmål for det meste. Du må sørge for å ta med DISTINCT skjønt.

Kommentarer

  • Dette er hyggelig, men er det en måte å unngå å gjenta overklausulen for alle kolonnene?

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 å legge ut bare kode, bør du prøve å forklare hvordan dette svarer på spørsmålet; og potensielt hva OP gjorde med feil.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *