Postgresql Выберите из диапазона дат между массивом дат - PullRequest
0 голосов
/ 13 января 2019

Если этот запрос возвращает даты, которые существуют в запрошенном диапазоне.

select created_at from user where created_at between '2015-01-06 00:00:00.000000' and '2015-03-06 00:00:00.000000'

Есть ли способ получить такой результат, но с несколькими датами, содержащими массив дат.

Просто для примера того, что я пытаюсь сказать. У меня есть этот массив дат, всегда будет первая и последняя дата.

Array['2015-01-06 00:00:00.000000','2015-02-10 15:17:18.895000' <- First range
      '2017-10-05 14:41:04.191000','2017-10-11 14:49:36.454000' <- Second range

так есть ли способ поставить скрипт, который выглядит примерно так?

select created_at from win_users 
where (created_at between [First Date] and [Second Date])
or (created_at between [Third Date] and [Fourth Date])

но без использования цикла для конкататации оператора where?

Ответы [ 2 ]

0 голосов
/ 13 января 2019

Массив дат в этом случае очень неудобен. Используйте массивы daterange и оператор удержания <@, например ::100100

with my_table(id, created_at) as (
values 
    (1, '2015-01-10'::timestamp),
    (2, '2016-05-10'),
    (3, '2017-10-10')
)

select *
from my_table
where created_at::date <@ any(array[daterange('2015-01-06','2015-02-10'), daterange('2017-10-05','2017-10-11')])

 id |     created_at      
----+---------------------
  1 | 2015-01-10 00:00:00
  3 | 2017-10-10 00:00:00
(2 rows)

Если вы абсолютно хотите использовать массив дат (честно говоря, я так не думаю), используйте эту функцию для преобразования его в массив дат:

create or replace function date_pairs_to_ranges(date[])
returns daterange[] language sql as $$
    select array_agg(daterange(d1, d2))
    from unnest($1) with ordinality as u1(d1, o1)
    join unnest($1) with ordinality as u2(d2, o2)
    on o1/ 2* 2 < o1 and o2 = o1+ 1
$$;

with my_table(id, created_at) as (
values 
    (1, '2015-01-10'::timestamp),
    (2, '2016-05-10'),
    (3, '2017-10-10')
)

select *
from my_table
where created_at::date <@ any(date_pairs_to_ranges(array['2015-01-06','2015-02-10','2017-10-05','2017-10-11']::date[]))
0 голосов
/ 13 января 2019

Если ваш массив диапазонов всегда находится в формате, который вы разместили (то есть 4 элемента с первыми двумя элементами, являющимися первым диапазоном, а последние два - вторым диапазоном), тогда вы можете написать запрос следующим образом:

WITH ranges AS (
    SELECT '{2015-01-06 00:00:00.000000,2015-02-10 15:17:18.895000,2017-10-05 14:41:04.191000,2017-10-11 14:49:36.454000}'::date[] dates
)
    SELECT win_users.created_at FROM win_users, ranges
        WHERE (win_users.created_at > ranges.dates[1] AND win_users.created_at < ranges.dates[2]) OR (win_users.created_at > ranges.dates[3] AND win_users.created_at < ranges.dates[4]);
...