Выберите только значения MIN в ORACLE SQL - PullRequest
2 голосов
/ 01 марта 2012

Я хочу выбрать самые ранние дату и время из моего набора данных и показывать только те строки, которые соответствуют требованию.И показать 3 столбца.

Я получил это, чтобы показать данные в правильном порядке по дате и времени.Как я могу просто заставить его отображать данные с минимальными значениями?Я попытался использовать first, limit и top x, но они не работают и не совсем то, что мне нужно, так как ответ может иметь более 1 значения.

Вот мой пример sql:

Select report, date, time
  From events
 order by date, time

Ответы [ 3 ]

4 голосов
/ 01 марта 2012

Попробуйте это:

 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 
1 голос
/ 01 марта 2012

Примерно так должно работать, если предположить, что каждая строка имеет правильно отформатированный компонент даты и времени.

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

Однако с точки зрения модели данных следует всегда хранить даты в столбцах DATE, а не впытаясь сохранить их в VARCHAR2 столбцах.Поскольку вам нужно сравнение дат и семантика сортировки, вам придется преобразовать данные в DATE, что является дорогостоящим во время выполнения.И есть большая вероятность, что кто-то в конечном итоге сохранит данные в другом формате в столбце или сохранит недопустимую строку (например, день «02/29/2011»), что приведет к тому, что ваш запрос начнет генерировать ошибки.

1 голос
/ 01 марта 2012

Немного догадываюсь, что типы данных не ясны, но что-то вроде этого может сработать (например, использование CTE для создания фиктивных данных):

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

Возможно, у вас другая маска формата даты;Я предположил, что в американском формате вы упомянули «военное время».

В зависимости от того, как вы хотите относиться к связям, вам понадобится rank или dense_rank вместо row_number.См. Документацию аналитические функции для получения дополнительной информации.Как указал Джастин, вы, вероятно, хотите rank, который с теми же данными дает:

REPORT  DATE_FIELD TIME
------- ---------- ----
report1 01/01/2012 0800
report2 01/01/2012 0900
report2 01/01/2012 0900

Внутренний выбор добавляет дополнительный столбец rn, который присваивает ранжирование каждому результату;каждое значение report будет иметь по крайней мере одну строку, которой присваивается 1 (если используется rank, в противном случае ровно одна), и, возможно, строки с 2, 3 и т. д. Одна или несколько строк с 1 будет иметь самую раннюю дату / время для этого отчета.Внешний запрос затем фильтрует до only , отображая ранжированные 1 с помощью предложения where rn = 1, следовательно, предоставляя данные только с самой ранней датой / временем для каждого report - остальное отбрасывается.

...