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.

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


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.


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
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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.