PostgreSQL:构造一个占用日期范围的查询

时间:2013-10-12 05:16:56

标签: python postgresql optimization

我有一个函数,它将日期范围作为输入并返回一个字典。我正在使用for循环。我想在PostgreSQL中做一切。什么是最好的方式?

功能体:

ids = {}

for current_date in rrule.rrule(rrule.DAILY, dtstart=start_date,
                                until=end_date):
    id = sql.with_query_result("""
            SELECT id
            FROM record
            WHERE type='default'

            UNION

            SELECT id
            FROM record
            WHERE extract(isodow from (:current_date)::timestamp) IN day_ids

            UNION

            SELECT id
            FROM record
            WHERE utc_dates @> (:current_date)::timestamp

            ORDER BY priority DESC
            LIMIT 1
            """, {'current_date': current_date})
    ids[current_date] = id

模式:

id integer
type text
day_ids integer[]
utc_dates tsrange
priority integer

2 个答案:

答案 0 :(得分:1)

这是我尝试没有数据进行测试而不知道sql.with_query_result驱动程序方法:

rs = sql.with_query_result("""
    select distinct on (_timestamp::date)
        _timestamp::date, id
    from
        record
        inner  join
        unnest(:current_date::timestamp[]) d(_timestamp) on
            utc_dates @> _timestamp
            or
            extract(isodow from _timestamp) = any(day_ids)
            or
            "type" = 'default'
    order by 1, priority desc
    """,
    {
        'current_date':
        rrule.rrule(rrule.DAILY, dtstart=start_date, until=end_date)
    }
)

ids = {}

for (current_date, id) in rs:
    ids[current_date] = id

答案 1 :(得分:0)

您可以在postgresql中实现python dateutil rrule。

CREATE OR REPLACE FUNCTION _pc_after(
    t_rule TEXT,
    t_after TIMESTAMP,
    inc BOOLEAN DEFAULT TRUE)
    RETURNS TIMESTAMP AS
$$
    from dateutil.rrule import *
    from dateutil.parser import *

    rule = rrulestr(t_rule)
    _after = parse(t_after)
    occurence = rule.before(_after, inc=False)
    return occurence
$$
LANGUAGE 'plpythonu' VOLATILE;

-- = simple before function =
CREATE OR REPLACE FUNCTION _pc_before(
    t_rule TEXT, 
    t_before TIMESTAMP,
    inc BOOLEAN DEFAULT TRUE) 
    RETURNS TIMESTAMP AS
$$
    from dateutil.rrule import *
    from dateutil.parser import *

    _rule = rrulestr(t_rule)
    _before = parse(t_before)
    occurence = _rule.before(_before, inc=False)
    return occurence
$$
LANGUAGE 'plpythonu' VOLATILE;

-- = simple between function =
CREATE OR REPLACE FUNCTION _pc_between(
    t_rule TEXT, 
    t_after TIMESTAMP, 
    t_before TIMESTAMP,
    inc BOOLEAN DEFAULT FALSE) 
    RETURNS SETOF TIMESTAMP AS
$$
    from dateutil.rrule import *
    from dateutil.parser import *

    _rule = rrulestr(t_rule)
    _after = parse(t_after)
    _before = parse(t_before)
    occurences = _rule.between(_after, _before, inc)

    return occurences
$$
LANGUAGE 'plpythonu' VOLATILE;

CREATE OR REPLACE FUNCTION _pc_between(
    t_rule TEXT, 
    t_after TIMESTAMP, 
    t_before TIMESTAMP,
    inc BOOLEAN DEFAULT FALSE) 
    RETURNS SETOF TIMESTAMP AS
$$
    from dateutil.rrule import *
    from dateutil.parser import *

    _rule = rrulestr(t_rule)
    _after = parse(t_after)
    _before = parse(t_before)
    occurences = _rule.between(_after, _before, inc)

    return occurences
$$
LANGUAGE 'plpythonu' VOLATILE;

所以:

SELECT _pc_between('DTSTART:20130102T090000
    RRULE:FREQ=DAILY;INTERVAL=10;COUNT=25',
    cast('2013-01-01' as timestamp),
    cast('2013-05-31' as timestamp)
);

将返回:

"2013-01-02 09:00:00"
"2013-01-12 09:00:00"
"2013-01-22 09:00:00"
"2013-02-01 09:00:00"
"2013-02-11 09:00:00"
"2013-02-21 09:00:00"
"2013-03-03 09:00:00"
"2013-03-13 09:00:00"
"2013-03-23 09:00:00"
"2013-04-02 09:00:00"
"2013-04-12 09:00:00"
"2013-04-22 09:00:00"
"2013-05-02 09:00:00"
"2013-05-12 09:00:00"
"2013-05-22 09:00:00"