เลือกวันที่มีวันที่สูงสุดหรือวันที่ล่าสุด


15

นี่คือสองตาราง

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

คน

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

นี่คือแบบสอบถามออราเคิลของฉัน

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;

ซึ่งให้ผลลัพธ์นี้

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

ฉันต้องการเลือกโรงเรียนแรกที่มีวันล่าสุด

ขอบคุณ

คำตอบ:


28

ข้อความค้นหาปัจจุบันของคุณไม่ได้ให้ผลลัพธ์ตามที่ต้องการเนื่องจากคุณใช้ส่วนGROUP BYคำสั่งในPERSON_IDคอลัมน์ที่มีค่าไม่ซ้ำกันสำหรับทั้งสองรายการ เป็นผลให้คุณจะกลับทั้งสองแถว

มีสองสามวิธีที่คุณสามารถแก้ไขปัญหานี้ได้ คุณสามารถใช้แบบสอบถามย่อยเพื่อใช้ฟังก์ชั่นรวมเพื่อส่งกลับmax(LAST_UPDATE_DATE_TIME)สำหรับแต่ละ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;

ดูSQL Fiddle พร้อมเดโม

หรือคุณสามารถใช้ฟังก์ชั่นหน้าต่างเพื่อส่งคืนแถวข้อมูลสำหรับแต่ละโรงเรียนด้วยข้อมูลล่าสุด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;

ดูSQL Fiddle พร้อมเดโม

แบบสอบถามนี้การดำเนินการrow_number()ซึ่งกำหนดจำนวนที่ไม่ซ้ำกันในแต่ละแถวในพาร์ติชันของและวางไว้ในลำดับถัดลงมาบนพื้นฐานของSCHOOL_CODELAST_UPDATE_DATE_TIME

ในฐานะที่เป็นข้อความด้านข้าง JOIN พร้อมฟังก์ชันการรวมไม่เหมือนกับrow_number()เวอร์ชั่นทุกประการ หากคุณมีสองแถวที่มีเวลากิจกรรมเดียวกัน JOIN จะส่งคืนทั้งสองแถวในขณะที่row_number()จะส่งคืนเพียงแถวเดียว หากคุณต้องการคืนค่าทั้งสองด้วยฟังก์ชั่น windowing ให้ลองใช้rank()ฟังก์ชั่น windowing แทนเพราะมันจะคืนค่าความสัมพันธ์:

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;

ดูการสาธิต


4

ฉันประหลาดใจที่ไม่มีใครได้ใช้ประโยชน์จากฟังก์ชั่นหน้าต่างเกินกว่า row_number ()

นี่คือข้อมูลที่จะเล่นกับ:

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

ประโยค OVER () สร้างหน้าต่างที่คุณจะกำหนดกลุ่มรวมของคุณ ในกรณีนี้ฉันแบ่งพาร์ติชันเฉพาะบน SHOOL_CODE เท่านั้นดังนั้นเราจะเห็น FIRST_VALUE ซึ่งจะมาจาก LAST_UPDATE_DATE_TIME จัดกลุ่มตาม SCHOOL_CODE และตามลำดับ LAST_UPDATE_DATE_TIME ตามลำดับจากมากไปหาน้อย ค่านี้จะนำไปใช้กับคอลัมน์ทั้งหมดสำหรับแต่ละ SCHOOL_CODE

มันเป็นสิ่งสำคัญที่จะต้องใส่ใจกับการแบ่งพาร์ติชันของคุณและการสั่งซื้อในประโยค 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

ผลตอบแทน:

24-JAN-13   ABE 111222

สิ่งนี้ควรขจัดความต้องการ GROUP BY และ Subqueries ของคุณเป็นส่วนใหญ่ คุณจะต้องแน่ใจว่าได้รวม 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
แทนที่จะโพสต์รหัสเพียงคุณควรพยายามอธิบายวิธีการนี้ตอบคำถาม; และอาจเป็นสิ่งที่ OP กำลังทำไม่ถูกต้อง
Max Vernon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.