2013-04-03 3 views
0

У меня есть следующая таблица дат:Oracle - выбор строки с минимальным значением в подгруппе

dateID INT (PK), 
personID INT (FK), 
date DATE, 
starttime VARCHAR, --Always in a format of 'HH:MM' 

То, что я хочу сделать, я хочу, чтобы тянуть строки (все столбцы, включая ПК) с низкой датой (основное условие) и время начала (вторичное условие) для каждого человека. Например, если мы имеем

ROW1 (дата = '2013-04-01' и время_запуска = '14: 00')

и

row2 (дата = '2013-04-02' и время начала = '08: 00 ')

строка 1 будет извлекаться вместе со всеми остальными столбцами.

До сих пор я придумывал постепенную фильтрацию стола, но это довольно беспорядок. Есть ли более эффективный способ сделать это?

Вот что я сделал до сих пор:

SELECT 
    D.id 
    , D.personid 
    , D.date   
    , D.starttime 
FROM table D 
JOIN (
     SELECT --Select lowest time from the subset of lowest dates 
      A.personid, 
      B.startdate, 
      MIN(A.starttime) AS starttime 
     FROM table A 
     JOIN (
       SELECT --Select lowest date for every person to exclude them from outer table 
        personid 
        , MIN(date) AS startdate 
       FROM table 
       GROUP BY personid 
      ) B 
     ON A.personid = B.peronid 
     AND A.date = B.startdate 
     GROUP BY 
      A.personid, 
      B.startdate 
    ) C 
ON C.personid = D.personid 
AND C.startdate = D.date 
AND C.starttime = D.starttime 

Это работает, но я думаю, что есть более чистый/эффективный способ сделать это. Есть идеи?

EDIT: Позвольте мне задать вопрос - мне также нужно извлечь максимальную дату (только дату, без времени) для каждого человека.

Результат должен выглядеть следующим образом:

id 
personid 
max(date) for each person 
min(date) for each person 
min(starttime) for min(date) for each person 

Это часть гораздо большего запроса (результирующая таблица соединяется с ним), и результирующая таблица должна быть достаточно легким, так что вона запрос `t выполнить слишком долго. При единственном соединении с этой таблицей (просто используя min, max для каждого поля, которое я хотел), запрос занял около 3 секунд, и я бы хотел, чтобы полученный результат не занимал больше 2-3 раз.

ответ

3

вы должны быть в состоянии сделать это, как:

select a.dateID, a.personID, a.date, a.max_date, a.starttime 
    from (select t.*, 
       max(t.date) over (partition by t.personID) max_date, 
       row_number() over (partition by t.personID 
            order by t.date, t.starttime) rn 
      from table t) a 
where a.rn = 1; 

выборочные данные добавлены поиграться: http://sqlfiddle.com/#!4/63c45/1

+0

Ответ хороший, но это очень неэффективно, когда в сочетании с остальной частью моего запроса. – kyooryu

+0

@kyooryu, возможно, если вы покажете остальную часть своего запроса? как то, что вы разместили, совпадает с ответом, который я предоставил с точки зрения результатов. вы можете изменить пример скрипки и опубликовать скрипку здесь, чтобы посмотреть. – DazzaL

+0

Я боюсь, что я не могу показать гораздо больше запросов, чем я уже опубликовал. Я немного расширил этот вопрос, так что вы можете увидеть, какой результат я буду присоединять к остальной части запроса. – kyooryu

0

Это запрос, вы можете использовать и нет необходимости включать в запросе. Вы можете также использовать @ запрос Dazzal как самостоятельные

SELECT ID, PERSONID, DATE, STARTTIME 
(
SELECT ID, PERONID, DATE, STARTTIME, ROW_NUMBER() OVER(PARTITION BY personid ORDER BY  STARTTIME, DATE) AS RN 
FROM TABLE 
) A 
WHERE 
RN = 1 
0
select a.id,a.accomp, a.accomp_name, a.start_year,a.end_year, a.company 
    from (select t.*, 
       min(t.start_year) over (partition by t.company) min_date, 
       max(t.end_year) over (partition by t.company) max_date, 
       row_number() over (partition by t.company 
            order by t.end_year desc) rn 
      from temp_123 t) a 
where a.rn = 1; 
Смежные вопросы