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;
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;
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ě.