Pilih yang memiliki tanggal maks atau tanggal terbaru

15

Berikut ini dua tabel.

STAF SEKOLAH

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

ORANG

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

Ini permintaan oracle saya.

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;

yang memberikan hasil ini

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

Saya ingin memilih yang pertama untuk sekolah yang memiliki tanggal terbaru.

Terima kasih.

riz
sumber

Jawaban:

28

Permintaan Anda saat ini tidak memberikan hasil yang diinginkan karena Anda menggunakan GROUP BYklausa pada PERSON_IDkolom yang memiliki nilai unik untuk kedua entri. Akibatnya, Anda akan mengembalikan kedua baris.

Ada beberapa cara untuk menyelesaikannya. Anda dapat menggunakan subquery untuk menerapkan fungsi agregat untuk mengembalikan max(LAST_UPDATE_DATE_TIME)masing-masing 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;

Lihat SQL Fiddle dengan Demo

Atau Anda dapat menggunakan fungsi windowing untuk mengembalikan baris data untuk setiap sekolah dengan yang terbaru 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;

Lihat SQL Fiddle dengan Demo

Query ini mengimplementasikan row_number()yang memberikan nomor unik untuk setiap baris dalam partisi SCHOOL_CODEdan ditempatkan dalam urutan menurun berdasarkan LAST_UPDATE_DATE_TIME.

Sebagai catatan, GABUNG dengan fungsi agregat tidak persis sama dengan row_number()versi. Jika Anda memiliki dua baris dengan waktu acara yang sama, GABUNG akan mengembalikan kedua baris, sedangkan row_number()hanya akan mengembalikan satu baris . Jika Anda ingin mengembalikan keduanya dengan fungsi windowing, maka pertimbangkan menggunakan rank()fungsi windowing karena akan mengembalikan ikatan:

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;

Lihat Demo

Taryn
sumber
4

Saya terkejut tidak ada yang memanfaatkan fungsi jendela di luar row_number ()

Berikut beberapa data untuk dimainkan:

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

Klausa OVER () menciptakan jendela di mana Anda akan mendefinisikan grup agregat Anda. Dalam hal ini, saya hanya mempartisi pada SHOOL_CODE, jadi kita akan melihat FIRST_VALUE, yang akan berasal dari LAST_UPDATE_DATE_TIME, dikelompokkan berdasarkan SCHOOL_CODE, dan dalam urutan LAST_UPDATE_DATE_TIME dengan urutan menurun. Nilai ini akan diterapkan ke seluruh kolom untuk setiap SCHOOL_CODE.

Penting untuk memperhatikan partisi dan pemesanan Anda di klausa 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

Pengembalian:

24-JAN-13   ABE 111222

Ini seharusnya menghilangkan kebutuhan Anda akan GROUP BY dan Subqueries untuk sebagian besar. Anda akan ingin memastikan untuk menyertakan DISTINCT.

Andrew
sumber
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
sumber
1
Alih-alih memposting kode yang adil , Anda harus mencoba menjelaskan bagaimana ini menjawab pertanyaan; dan berpotensi apa yang OP lakukan secara tidak benar.
Max Vernon