Vyberte, které má maximální datum nebo poslední datum

Zde jsou dvě tabulky.

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 

Zde je můj dotaz Oracle.

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ž dává tyto výsledky

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

Chci vybrat první školu, která má poslední datum.

Děkuji.

Odpověď

Váš aktuální dotaz neposkytuje požadovaný výsledek, protože používáte GROUP BY klauzule ve sloupci PERSON_ID, která má pro obě položky jedinečnou hodnotu. Ve výsledku vrátíte oba řádky.

Existuje několik způsobů, jak to vyřešit. Pomocí poddotazu můžete použít agregační funkci k vrácení max(LAST_UPDATE_DATE_TIME) pro každý 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; 

Viz SQL Fiddle with Demo

Nebo můžete použít funkce okna pro vrácení řádků dat pro každou školu s nejnovější 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; 

Viz SQL Fiddle with Demo

Tento dotaz implementuje row_number() , který každému řádku v oddílu SCHOOL_CODE přiřadí jedinečné číslo a umístí se v sestupném pořadí podle LAST_UPDATE_DATE_TIME.

Jako vedlejší poznámka, JOIN s agregační funkcí není úplně stejný jako verze row_number(). Pokud máte dva řádky se stejnou dobou události, JOIN vrátí oba řádky, zatímco row_number() vrátí pouze jeden. Pokud chcete vrátit oba s funkcí okna, zvažte místo toho použití rank() funkce okna, protože vrátí vazby:

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; 

Viz Demo

Komentáře

  • Díky, najdu vnitřní spojení s tabulkou poddotazů (příklad 1 výše) je nejintuitivnější .. a nevyžaduje ', abych se naučil, co je partition by vše o. Zde je pohled na podobnou syntaxi jako v příkladu 1: vyberte oT.dateField, oT.siteID, oT.field1, oT.field2, oT.field3, z originalTable jako oT vnitřní spojení (vyberte max (dateField) jako newestDate, siteID ze skupiny originalTable podle siteID) jako newTable na oT.siteID = newTable.site_ID a oT.dateField = newTable.newestDate pořadí od oT.siteID asc Pro mě to lépe vysvětluje, co ' děje se v poddotazu.

Odpovědět

I „Jsem překvapen, že nikdo nevyužil výhod okenních funkcí nad rámec row_number ()

Zde jsou některá data ke hraní:

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

Klauzule OVER () vytvoří okno, pro které definujete agregované skupiny. V tomto případě rozděluji pouze na SHOOL_CODE, takže uvidíme FIRST_VALUE, která bude pocházet z LAST_UPDATE_DATE_TIME, seskupena podle SCHOOL_CODE, a v pořadí LAST_UPDATE_DATE_TIME sestupně. Tato hodnota bude použita pro celý sloupec pro každý SCHOOL_CODE.

Je důležité věnovat zvláštní pozornost vašemu rozdělení a řazení v 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 

Vrací:

24-JAN-13 ABE 111222 

To by mělo eliminovat vaši potřebu GROUP BY a poddotazů z větší části. Určitě však budete chtít zahrnout DISTINCT.

Komentáře

  • To je hezké, ale existuje způsob, jak se vyhnout opakování klauzule over pro všechny sloupce?

odpověď

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) 

komentáře

  • Místo zveřejňování pouze kódu byste se měli pokusit vysvětlit, jak to odpovídá na otázku; a potenciálně to, co OP dělal nesprávně.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *