简体   繁体   中英

Obtaining the earliest date by day/month among different years

I have a list of dates:

Event dates

- 06/04/1998
- 12/08/1980
- 29/11/2010
- 16/06/2002
- 20/10/2007
- 10/07/2000

I wanna obtain the earliest event date by day/month among all these years. so the earliest is 06/04/1998 and if i wanna obtain the latest event date it is 29/11/2010. How do i write the syntax for this?

SELECT MAX(date), MIN(date), YEAR(date) year, MONTH(date) month
FROM table
GROUP BY YEAR(date), MONTH(date)

Note: This is pseudocode - you'll need to lookup what the correct function in oracle is to extract the year and month from a date.

You will also benefit from a function index on: YEAR(date), MONTH(date), date

SELECT EXTRACT( MONTH FROM date_column),
       EXTRACT( DAY   FROM date_column),
       EXTRACT( YEAR  FROM date_column),
       date_column
  FROM table
 ORDER BY 1, 2, 3

and to select the first record

SELECT *
  FROM (SELECT EXTRACT( MONTH FROM date_column),
               EXTRACT( DAY   FROM date_column),
               EXTRACT( YEAR  FROM date_column),
               date_column
          FROM table
         ORDER BY 1, 2, 3)
 WHERE rownum <= 1

Assuming I understand that you really do want the earliest date by day/month in any year, then an analytic function can do this:

select dt from (
    select dt,
        dense_rank() over (partition by 1 order by to_char(dt, 'MMDD'),
            to_char(dt, 'YYYY')) rn
    from t
)
where rn = 1;

DT
----------
06/04/1998

The inner select here is using dense_rank() to assign a ranking to each date, based on an ordering I specified - there are other ways to do this but converting the day/month to a string seems to work, and I included the year to break ties if you have the same day/month in more than one year (guessing you'd want the earliest year in that case). Just that on its own, with a few extra dates added, looks like this:

alter session set nls_date_format = 'DD/MM/YYYY';
with t as (
    select to_date('06/04/1998') as dt from dual
    union all select to_date('12/08/1980') from dual
    union all select to_date('29/11/2010') from dual
    union all select to_date('16/06/2002') from dual
    union all select to_date('20/10/2007') from dual
    union all select to_date('10/07/2000') from dual
    union all select to_date('10/07/1999') from dual
    union all select to_date('06/04/1999') from dual
)
select dt,
    dense_rank() over (partition by 1 order by to_char(dt, 'MMDD'),
        to_char(dt, 'YYYY')) rn
from t;

DT         RN
---------- ----------
06/04/1998      1
06/04/1999      2
16/06/2002      3
10/07/1999      4
10/07/2000      5
12/08/1980      6
20/10/2007      7
29/11/2010      8

8 rows selected.

The outer select just picks the dt values with rank rn = 1 .

If you want to find the latest, change the order by clauses to include desc so they're sorted in reverse order.

how about following:

select date from ... where rownum = 1 order by month(date) * 100 + day(date) desc

select date from ... where rownum = 1 order by month(date) * 100 + day(date) asc

If that list already has in table.

Just SELECT Max(fieldName) or Min(fieldName)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM