如果日期行不存在,则按日期数组和第二天进行选择?

时间:2018-12-10 08:16:04

标签: sql postgresql

我想知道从一行日期进行日期比较时是否可以同时运行IN条件和>条件(仅在IN中找不到)?

例如,如果不存在2018-01-01,它将拉出日期2018-01-02的下一个可用行,并且应该对我提供的随机日期数组执行此操作。 (请勿更改,因为这会输入我不感兴趣的日期。)

示例:

create table trade (
    id serial primary key,
    year int,
    month int,
    "data" json
);

insert into trade ("year", "month", "data") VALUES (
  2018, 1, '{"2": {"low": 19, "high": 21, "open": 20, "close": 20, "volume": 1000}, "3": {"low": 19, "high": 21, "open": 20, "close": 20, "volume": 1000}}'::json
);

insert into trade ("year", "month", "data") VALUES (
  2018, 2, '{"1": {"low": 19, "high": 21, "open": 20, "close": 20, "volume": 1000}, "2": {"low": 19, "high": 21, "open": 20, "close": 20, "volume": 1000}}'::json

SELECT
 t.prices,
 make_date("year", "month", t.day::int) as date
FROM
trade
JOIN json_each(trade.data) t(day, prices) ON TRUE
WHERE
make_date("year", "month", t.day::int) IN ('2018-01-1', '2018-01-03')
);

希望它返回1950-01-03、2018-01-03和2018-01-02的价格(因为不存在2018-01-01)

我正在开发一个函数,当我提供感兴趣的日期时,它将以1/1的比例显示结果,如果不存在,它将返回下一个可用日期。

2 个答案:

答案 0 :(得分:1)

您可以使用generate_series检查给定范围内的所有日期。

SELECT
 t.prices,
 make_date("year", "month", t.day::int) as date
FROM
trade
JOIN json_each(trade.data) t(day, prices) ON TRUE
WHERE
("year"|| lpad( "month"::text,2,'0') || lpad(t.day,2,'0') )::DATE -- a simulation of 
                                                                 --your make_date function.

IN ( select 
           generate_series(DATE '2018-01-1',
                   DATE '2018-01-03',INTERVAL '1 DAY') ::DATE
);

Demo

修改

  

假设我想在1950年1月1日,2001年1月1日和2002年1月4日约会,   等等

您可以在UNION ALL

中使用多个范围
..
IN ( select 
           generate_series(DATE '2018-01-1',
                   DATE '2018-01-03',INTERVAL '1 DAY') ::DATE
                   UNION ALL
     select 
           generate_series(DATE '1950-01-01',
                   DATE '1950-01-03',INTERVAL '1 DAY') ::DATE    
                   UNION ALL
     select 
           generate_series(DATE '2002-01-01',
                   DATE '2002-01-04',INTERVAL '1 DAY') ::DATE                  

)
..
..

答案 1 :(得分:1)

假设差距可能大于一天,那么以下功能似乎是最简单有效的解决方案:

create or replace function trade_on_dates(variadic date[])
returns table (prices json, date date) 
language plpgsql stable as $$
declare
    d date;
begin
    foreach d in array $1 loop
        return query select
            t.prices,
            make_date("year", "month", t.day::int) as date
        from trade
        join json_each(trade.data) t(day, prices) on true
        where make_date("year", "month", t.day::int) >= d
        order by 2
        limit 1;
    end loop;
end $$;

select *
from trade_on_dates('2018-01-01', '2018-01-03');

                              prices                              |    date    
------------------------------------------------------------------+------------
 {"low": 19, "high": 21, "open": 20, "close": 20, "volume": 1000} | 2018-01-02
 {"low": 19, "high": 21, "open": 20, "close": 20, "volume": 1000} | 2018-01-03
(2 rows)