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.

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


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.


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)

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.