Hangisinin maksimum tarih veya en son tarih olduğunu seçin


15

İşte iki tablo.

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

KİŞİLER

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

İşte benim kehanet sorgu.

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;

bu da bu sonuçları verir

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

En son tarihli okul için ilkini seçmek istiyorum.

Teşekkürler.

Yanıtlar:


28

Her iki giriş için benzersiz bir değere sahip GROUP BYolan PERSON_IDsütunda bir cümle kullandığınızdan, geçerli sorgunuz istenen sonucu vermiyor. Sonuç olarak her iki satırı da döndürürsünüz.

Bunu çözmenin birkaç yolu vardır. max(LAST_UPDATE_DATE_TIME)Her biri için dönmek üzere toplama işlevini uygulamak üzere bir alt sorgu kullanabilirsiniz 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;

Demo ile SQL Fiddle'ı görün

Veya her okul için en yeni veri satırlarını döndürmek üzere bir pencereleme işlevi kullanabilirsiniz 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;

Demo ile SQL Fiddle'ı görün

Bu sorgu row_number(), bölümünde her satıra benzersiz bir sayı atayan SCHOOL_CODEve LAST_UPDATE_DATE_TIME.

Bir yan not olarak, toplama işlevli JOIN, row_number()sürümle tam olarak aynı değildir . Aynı olay süresine sahip iki satırınız varsa, JOIN her iki satırı da döndürür row_number(), yalnızca bir satır döndürür. Her ikisini de bir pencereleme işleviyle döndürmek istiyorsanız, rank()bağları döndüreceği için pencereleme işlevini kullanmayı düşünün :

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;

Demoya Bakın


4

Kimse row_number () ötesinde pencere işlevlerinden yararlanmak şaşırttı

İşte oynamak için bazı veriler:

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 () deyimi, toplu gruplarınızı tanımlayacağınız bir pencere oluşturur. Bu durumda, sadece SHOOL_CODE üzerinde bölümleme yapıyorum, bu yüzden LAST_UPDATE_DATE_TIME, SCHOOL_CODE tarafından gruplandırılmış ve LAST_UPDATE_DATE_TIME sırasına göre azalan sıraya göre FIRST_VALUE'yu göreceğiz. Bu değer, her SCHOOL_CODE için tüm sütuna uygulanır.

Over () maddesindeki bölümleme ve siparişlerinize çok dikkat etmek önemlidir.

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

İadeler:

24-JAN-13   ABE 111222

Bu çoğunlukla GROUP BY ve Subqueries ihtiyacınızı ortadan kaldırmalıdır. Yine de DISTINCT'i eklediğinizden emin olmak istersiniz.


Bu güzel, ancak tüm sütunlar için aşırı maddeyi tekrar etmenin bir yolu var mı?
static_rtti

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
Sadece kod göndermek yerine, bunun soruyu nasıl cevapladığını açıklamaya çalışmalısınız; ve potansiyel olarak OP'nin yanlış yaptığı şey.
Max Vernon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.