Välj vilket maxdatum eller senaste datum

Här är två 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 

Här är min orakelfråga.

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; 

vilket ger dessa resultat

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

Jag vill välja den första för skolan som har senaste datum.

Tack.

Svar

Din nuvarande fråga ger inte önskat resultat eftersom du använder en GROUP BY sats i kolumnen PERSON_ID som har ett unikt värde för båda posterna. Som ett resultat kommer du att returnera båda raderna.

Det finns några sätt att lösa detta. Du kan använda en underfråga för att tillämpa den samlade funktionen för att returnera max(LAST_UPDATE_DATE_TIME) för varje 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-fiol med demo

Eller så kan du använda en fönsterfunktion för att returnera dataraderna för varje skola med den senaste 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 Fiddle with Demo

Denna fråga implementerar row_number() som tilldelar varje rad ett unikt nummer i partitionen av SCHOOL_CODE och placeras i en fallande ordning baserat på LAST_UPDATE_DATE_TIME.

Som en sidoteckning är JOIN med aggregerad funktion inte exakt densamma som row_number() -versionen. Om du har två rader med samma händelsetid kommer JOIN att returnera båda raderna, medan row_number() bara returnerar en. Om du vill returnera båda med en fönsterfunktion kan du överväga att använda rank() fönsterfunktionen istället eftersom den returnerar band:

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

  • Tack, jag tycker den inre kopplingen till en undersökningstabell (exempel 1 ovan) för att vara den mest intuitiva .. och kräver inte ' mig att lära mig vad partition av är allt handla om. Här är en titt på en liknande syntax som exempel 1: välj oT.dateField, oT.siteID, oT.field1, oT.field2, oT.field3, från originalTable som oT inner join (välj max (dateField) som newestDate, siteID från originalTable group by siteID) som newTable på oT.siteID = newTable.site_ID och oT.dateField = newTable.newestDate order av oT.siteID asc För mig förklarar det bättre vad ' händer i underfrågan.

Svar

I ”Jag är förvånad över att ingen har utnyttjat fönsterfunktioner bortom radnummer ()

Här är lite data att spela 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 () sats skapar ett fönster för vilket du definierar dina aggregerade grupper. I det här fallet partitionerar jag bara på SHOOL_CODE, så vi kommer att se FIRST_VALUE, som kommer från LAST_UPDATE_DATE_TIME, grupperad efter SCHOOL_CODE, och i ordningen LAST_UPDATE_DATE_TIME efter fallande ordning. Detta värde kommer att tillämpas på hela kolumnen för varje SCHOOL_CODE.

Det är viktigt att vara noga med din partitionering och beställning i över () 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 

Returnerar:

24-JAN-13 ABE 111222 

Detta bör eliminera ditt behov av GROUP BY och underfrågor för det mesta. Du vill dock se till att ta med DISTINCT dock.

Kommentarer

  • Det här är trevligt, men finns det ett sätt att undvika att upprepa överklausulen för alla kolumner?

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 stället för att posta bara kod bör du försöka förklara hur detta svarar på frågan; och eventuellt vad OP gjorde felaktigt.

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *