2017-02-10 5 views
4

Предположим, что у меня есть таблица, которая выглядит так, что дает мне время различных событий за считанные секунды.SQL: выберите строки только со значениями, разделенными заданным интервалом, из других результатов.

event_time 
---------- 
11 
14 
18 
20 
25 
39 
42 
43 
50 

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

Желаемый результат был бы:

event_time 
---------- 
11 
25 
39 
50 

В строке с event_time=11 включен, потому что нет ничего предшествующих ему. Строка с event_time=25 является следующей, которая будет возвращена, потому что это первая строка, которая находится не менее 10 секунд от строки с event_time=11.

Я использую Postgres. Я мог бы сделать это с помощью рекурсивного запроса/CTE, но не могу сделать эту работу без использования предложения ORDER BY, LIMIT и т. Д., И Postgres, по-видимому, не допускает их в рекурсивных запросах.

+0

Какой язык программирования содержит SQL? Зачем пытаться делать это с помощью SQL? – Apalala

+1

Потому что я хотел бы, чтобы это оценивалось в базе данных, если это вообще возможно, и не полагаться на передачу всего набора данных по сети, которая будет обрабатываться на клиенте. – avalys

+0

Для этого вам нужно использовать рекурсивный CTE. Если у вас много данных, это может быть более эффективным для этого на стороне приложения. –

ответ

2

I would be able to do this with a recursive query/CTE, but cannot make that work without using an ORDER BY, LIMIT, etc. clause, and Postgres apparently does not allow these in recursive queries.

with recursive 
    t(x) as (--Test data 
    select * from unnest('{11,14,18,20,25,39,42,43,50,55,60,61,69,70,71}'::int[]) 
    order by random()), 
    r(x) as (
    select min(x) as x from t 
    union all 
    (select t.x from t join r on (t.x >= r.x + 10) order by t.x limit 1)) 
select * from r; 

http://rextester.com/VHOGH66762

Но лично я предпочитаю the solution with stored function.

+0

Отлично! Это почти то, что я пробовал, но без круглых скобок, окружающих оператор, следующий за «union all», он терпит неудачу с «ERROR: LIMIT в рекурсивном запросе не реализовано». – avalys

+0

@avalys На самом деле это обычно для предложения 'union'. Просто сравните: http://rextester.com/FUO17127 – Abelisto

+0

Запрос действительно прекрасен и заслуживает того, чтобы его приняли. Я бы добавил лишь какое-то предупреждение, вы не должны использовать его для большого набора данных. Мое простое решение plpgsql будет во много раз быстрее. – klin

2

Вы можете использовать plpgsql, который кажется простым и достаточно эффективным для большого набора данных (по сравнению с гипотетическим рекурсивным запросом).

create or replace function strain_events() 
returns setof events language plpgsql as $$ 
declare 
    curr record; 
    prev int; 
begin 
    for curr in 
     select * 
     from events 
     order by 1 
    loop 
     if prev is null or curr.event_time >= prev + 10 then 
      return next curr; 
      prev = curr.event_time; 
     end if; 
    end loop; 
end $$; 

select * from strain_events(); 
+1

Это была моя идея. но это прерывается, если есть событие с разницей ровно 10. –

+0

Поскольку моя первая попытка не увенчалась успехом, я отправляю альтернативное решение. – klin

0

Я думаю, что этот запрос будет работать

select distinct event_time_b 
from 
(
select event_time_a , min(event_time_b) event_time_b 
from 
(
select a.event_time event_time_a , b.event_time event_time_b , b.event_time-a.event_time diff 
from (select 0 as event_time union select event_time from so_ques) a , so_ques b 
where a.event_time<>b.event_time 
and b.event_time-a.event_time>=10 
order by a.event_time 
) a 
group by event_time_a 
order by event_time_a 
) a 
order by 1 
; 

ИмяТаблицы = so_ques (создана для тестирования)

+0

Не работает. Пробовал это. Проверьте этот случай: «вставляйте в значения so_ques (11), (14), (18), (20), (25), (39), (42), (43), (50), (55), (60), (61), (69), (70), (71); ' –

Смежные вопросы