Wählen Sie das Höchstdatum oder das späteste Datum aus

15

Hier sind zwei Tabellen.

SCHULPERSONAL

SCHOOL_CODE + STAFF_TYPE_NAME + LAST_UPDATE_DATE_TIME + PERSON_ID
=================================================================
ABE           Principal         24-JAN-13               111222
ABE           Principal         09-FEB-12               222111

PERSONEN

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

Hier ist meine Orakelfrage.

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;

was diese Ergebnisse gibt

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

Ich möchte den ersten für die Schule auswählen, der das späteste Datum hat.

Vielen Dank.

riz
quelle

Antworten:

28

Ihre aktuelle Abfrage liefert nicht das gewünschte Ergebnis, da Sie eine GROUP BYKlausel in der PERSON_IDSpalte verwenden, die für beide Einträge einen eindeutigen Wert hat. Als Ergebnis geben Sie beide Zeilen zurück.

Es gibt verschiedene Möglichkeiten, dies zu lösen. Sie können eine Unterabfrage verwenden , um die Aggregatfunktion anzuwenden , um die Rückkehr max(LAST_UPDATE_DATE_TIME)für jeden 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;

Siehe SQL Fiddle with Demo

Oder Sie können eine Fensterfunktion verwenden , um die Datenzeilen für jede Schule mit den neuesten Daten zurückzugeben 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;

Siehe SQL Fiddle with Demo

Diese Abfrage wird implementiert row_number() die Zuordnung einer eindeutigen Nummer zu jeder Zeile in der Partition von SCHOOL_CODEund platziert in absteigender Reihenfolge basierend auf der LAST_UPDATE_DATE_TIME.

Als Randnotiz ist die JOIN mit Aggregat-Funktion nicht genau die gleiche wie die row_number()Version. Wenn Sie zwei Zeilen mit derselben Ereigniszeit haben, gibt JOIN beide Zeilen zurück, während JOIN row_number()nur eine zurückgibt. Wenn Sie beide mit einer Fensterfunktion zurückgeben möchten, sollten Sie die verwendenrank() stattdessen Fensterfunktion verwenden, da sie Bindungen zurückgibt:

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;

Siehe Demo

Taryn
quelle
4

Ich bin überrascht, dass niemand über row_number () hinaus Fensterfunktionen ausgenutzt hat.

Hier sind einige Daten zum Spielen:

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

Die OVER () -Klausel erstellt ein Fenster, für das Sie Ihre Aggregatgruppen definieren. In diesem Fall partitioniere ich nur den SHOOL_CODE, sodass wir den FIRST_VALUE sehen, der von LAST_UPDATE_DATE_TIME kommt, gruppiert nach SCHOOL_CODE und in absteigender Reihenfolge nach LAST_UPDATE_DATE_TIME. Dieser Wert wird für jeden SCHOOL_CODE auf die gesamte Spalte angewendet.

Es ist wichtig, dass Sie Ihre Partitionierung und Reihenfolge in der over () -Klausel genau beachten.

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

Kehrt zurück:

24-JAN-13   ABE 111222

Dies sollte Ihre Notwendigkeit für GROUP BY und Unterabfragen zum größten Teil beseitigen. Sie sollten jedoch sicherstellen, dass DISTINCT enthalten ist.

Andrew
quelle
1
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)
MouseInfa
quelle
1
Anstatt nur Code zu veröffentlichen, sollten Sie versuchen zu erklären, wie dies die Frage beantwortet. und möglicherweise, was das OP falsch tat.
Max Vernon