Как выбрать на основе максимального временного интервала - PullRequest
1 голос
/ 18 августа 2011

В Postgres SQL 8.4 у меня есть следующая таблица:

 1   | John Smith | 2011-08-12 12:44:13.125+08
 2   | John Smith | 2011-08-16 08:38:57.968+08
 3   | John Smith | 2011-08-16 08:38:58.062+08
 4   | Kenny Long | 2011-08-16 17:06:35.843+08
 5   | Kenny Long | 2011-08-16 17:06:35.906+08
 6   | Kenny Long | 2011-08-16 17:06:59.281+08
 7   | Kenny Long | 2011-08-16 17:07:00.234+08
 8   | Kenny Long | 2011-08-16 17:07:32.859+08
 9   | Kenny Long | 2011-08-16 17:08:00.437+08
 10  | Kenny Long | 2011-08-16 17:08:22.718+08
 11  | Kenny Long | 2011-08-16 17:08:22.781+08

Я бы хотел выбрать метку времени на основе столбцов.Только одна строка необходима для тех записей, которые находятся в пределах 2 минут друг от друга.Например, записи с номерами от 4 до 9 должны возвращать только номер строки 4 и игнорировать остальные строки.

Как этого добиться?Мы высоко ценим вашу помощь.

Заранее благодарим.

Джо Лью

Ответы [ 2 ]

1 голос
/ 19 августа 2011

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

Но это сработало на моем тестовом примере.Цель состоит в том, чтобы начать с одной минимальной временной отметки на парня, а затем отследить, какие строки должны быть удалены (в пределах 2-минутного диапазона), и какая строка является следующей действительной.Затем на каждой итерации мы продолжаем с этой действительной строки (по одной на парня).

Итак, вот запрос для таблицы myschema.mytable с столбцами id, name, tm.Обратите внимание, что столбец уровня предназначен только для отслеживания рекурсии и отладки, необязательно:

WITH RECURSIVE mytmp(id,name,thetime,thelevel) AS (
   -- recursive query: 1st row
   -- starting point, one row of the table for each people
   -- with a subquery to get the min time with id, maybe a better way to do it
   (
    select myschema.mytable.id,myschema.mytable.name,myschema.mytable.tm as thetime,1 as thelevel
    from (
      select name,min(tm) as mintm
      from myschema.mytable
      group by name
     ) q,myschema.mytable
    WHERE myschema.mytable.name=q.name
    AND myschema.mytable.tm=q.mintm
   ORDER BY name ASC) -- end of starting point of recursive query
  UNION ALL 
    -- now the recursive part, starting from the 1st row and then again and again (loop)
    -- get descendants in the 2 minutes interval for every computed row already in mytmp
    --
    -- get from previous iterations targets, one per guy
    -- and track the 1st new valid row (>2min) for that guy
    -- removing bad rows (<2min) is easy, several way to do it
    -- keeping only one valid row (and not all the others is harder, limit and aggregates functions are restricted in recursive terms
    -- we must keep only one, as the future valid rows will depend on the 2 minutes range from this one
    -- maybe some window function could help me, but at least I've a working solution
    select myschema.mytable.id,myschema.mytable.name,myschema.mytable.tm as thetime,q2.thelevel
    FROM myschema.mytable,(
    -- here need to keep 1st true one
    select myschema.mytable.name,MIN(myschema.mytable.tm) as tm,mytmp2.thelevel +1 as thelevel
    FROM myschema.mytable,(
        select id,name,thetime,thelevel
        from mytmp 
    ) mytmp2
    -- hack: mytmp2 is useless, mytmp should have been used
    -- we create this indirection to avoid this message:
    -- "ERROR:  aggregate functions not allowed in a recursive query's recursive term"
    -- on the MIN functions
    -- I do not know why it worked :-)
    WHERE myschema.mytable.name=mytmp2.name
    -- future
    AND myschema.mytable.tm - mytmp2.thetime > INTERVAL '0'
    GROUP BY
        -- hack the group by, to make 2 groups
        -- the first one for rows in the 2 min range and the second one for others
        CASE WHEN ((myschema.mytable.tm - mytmp2.thetime) > INTERVAL '2 minutes') THEN 1 ELSE 2 END,
        myschema.mytable.name,mytmp2.thelevel,mytmp2.thetime
        -- then with the having we keep only the second group, containing the first valid > 2min row
        HAVING ((MIN(myschema.mytable.tm) - mytmp2.thetime) > INTERVAL '2 minutes')=true
    ) q2 -- q2contains 1st true row and all false rows for each people
    -- q2 is used to get the id, that we cannot have in a group by request
    WHERE q2.tm=myschema.mytable.tm
    AND q2.name=myschema.mytable.name
 ) -- end of recursive query
  SELECT *
  FROM mytmp
  ORDER BY name asc, thelevel asc,thetime asc
  -- LIMIT 100 -- to debug, avoid infinite loops

Другое решение может заключаться в использовании хранимой процедуры , выполняющей те же действия во временной таблице.(возьмите действительные строки, удалите строки в диапазоне 2 мин, затем возьмите следующие действительные и т. д.), возможно, проще в обслуживании.

0 голосов
/ 19 августа 2011

Просто какая-то идея, не проверенная.Оконная функция должна быть 8,4 или более поздней.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...