Reputation: 239
I want to select the earliest date and time from my data set and only show those row(s) that fit the requirement. And show 3 columns.
I got it to show the data in the right order by date and time. How can I just get it to show the data that have the mininum values? I tried using first, limit, and top x, but they don't work, and aren't exactly what I need since the answer may have more than 1 value.
Here is my example sql:
Select report, date, time
From events
order by date, time
Upvotes: 2
Views: 10249
Reputation: 191265
Guessing a bit as the data types aren't clear, but something like this might work (example using a CTE to generate dummy data):
with events as (
select 'report1' as report, '01/01/2012' as date_field, '0800' as time_field
from dual
union all select 'report1', '01/01/2012', '0900' from dual
union all select 'report1', '01/02/2012', '0930' from dual
union all select 'report2', '01/01/2012', '0900' from dual
union all select 'report2', '01/01/2012', '0900' from dual
union all select 'report2', '01/01/2012', '1000' from dual
)
select report, date_field, time_field
from (
select report, date_field, time_field,
row_number() over (partition by report
order by to_date(date_field, 'MM/DD/YYYY'), time_field) as rn
from events
)
where rn = 1
order by report;
REPORT DATE_FIELD TIME
------- ---------- ----
report1 01/01/2012 0800
report2 01/01/2012 0900
You may have a different date format mask; I've assumed US format as you referred to 'military time'.
Depending on how you want to treat ties, you'll want rank
or dense_rank
instead of row_number
. See the documentation of analytic functions for more info. As Justin pointed out you probably want rank
, which with the same data gives:
REPORT DATE_FIELD TIME
------- ---------- ----
report1 01/01/2012 0800
report2 01/01/2012 0900
report2 01/01/2012 0900
The inner select adds an extra rn
column that assigns a ranking to each result; each value of report
will have at least one row that gets assigned 1
(if using rank
, otherwise exactly one), and possibly rows with 2
, 3
etc. The one(s) with 1
will have the earliest date/time for that report. The outer query then filters to only show those ranked 1
, via the where rn = 1
clause, hence only giving the data with the earliest date/time for each report
- the rest is discarded.
Upvotes: 1
Reputation: 231661
Something like this should work assuming that every row has a validly formatted day and time component.
SELECT report,
dt,
time
FROM (SELECT report,
dt,
time,
rank() over (partition by report
order by to_date( dt || ' ' || time, 'MM/DD/YYYY HH24MI' ) asc) rnk
FROM events)
WHERE rnk = 1
From a data model standpoint, however, you should always store dates in DATE
columns rather than trying to store them in VARCHAR2
columns. Since you want date comparison and sorting semantics, you'll have to transform the data into a DATE
which is costly at runtime. And there is a great chance that someone will eventually store data in a different format in the column or store an invalid string (i.e. a day of '02/29/2011') which will cause your query to start generating errors.
Upvotes: 1
Reputation: 1096
Try this:
SELECT report, date, time
FROM (SELECT report, date, time,
ROW_NUMBER() OVER(PARTITION BY report ORDER BY date ASC, time ASC) AS RowNum
From events
) AS CTE
WHERE CTE.RowNum = 1
Upvotes: 4