【问题标题】:postgres how to materialize a row for each value in an enum arraypostgres如何为枚举数组中的每个值实现一行
【发布时间】:2015-10-23 14:21:22
【问题描述】:

我有一个 postgres 表,用于存储名为 appointments 的定期约会。我还有一个名为day_of_week 的枚举类型。

day_of_week 是一个看起来像这样的枚举:

select enum_range(null::ck_day_of_week);

返回

{Monday,Tuesday,Thursday,Sunday,Saturday,Friday,Wednesday}

约会表的 DDL 是:

create table appointments
(
    id serial primary key not null,
    title varchar not null
    recurrence_start_date timestampz not null,
    recurrence_end_date timestampz,
    recurrence_days_of_week _ck_day_of_week  -- this is actually an array of enums, not just an enum. I don't fully understand why the DDL looks like this
);

一个查询

select id, title, recurrence_days_of_week from appointments where recurrence_start_date <= now() and (recurrence_end_date is null or recurrence_end_date >= now());

返回如下内容:

1,My Recurring Appointment,{Wednesday,Thursday,Friday,Saturday,Sunday}

我的问题是,我需要将此结果“具体化”为 UI 视图的一组行。具体来说,我想查询数据库并让它返回如下行:

id,My Recurring Appointment,date

其中唯一键可能是约会 ID 和特定 date,而 date 本质上是recurrence_start_date + 星期几的组合(星期几是0 到6 之间的偏移量)。

在 postgres 中,如何从具有枚举数组列的表中进行选择,并让它为数组中的每个枚举值返回 --real-- 同一行的 --virtual- 单行?我正在考虑一个视图或其他东西,但我现在确定如何编写 select 语句。

如果这可以翻译成 SQLAlchemy 加分....

我也打开并考虑创建一个约会表来存储每个约会及其特定日期。但如果我这样做......理论上,对于没有结束日期的重复日期的约会,表格可能会无限大,所以我一直在努力避免这种情况。

【问题讨论】:

    标签: python postgresql sqlalchemy


    【解决方案1】:

    首先,我不建议使用 id 作为列名。

    其次,我会使用内置的日期/时间函数来实现第一个目标。更具体地说,extract 函数与 dow 参数(星期几)和 generate_series 函数的组合。

    请务必检查 References 部分中的 fiddle。

    查询一周中每一天的appointments返回列表:

    create or replace function fnc_appointment_list_dow_by_id(_app_id int)
        returns table (__app_id int, __title varchar, __recurrence_start_date timestamptz, __recurrence_appointment_day timestamptz, __reccurence_dow_offset int) as
    $body$
            select
                    app.app_id,
                    app.app_title,
                    app.app_recurrence_start_date,
                    _appointment_days._day,
                    extract(dow from _day)::int
                from
                    appointments app,
                    generate_series(app.app_recurrence_start_date, app.app_recurrence_end_date, interval '1 day') _appointment_days(_day)
                where app.app_id=_app_id;
    $body$
        language sql stable; -- consider changing function volatility as needed.
    
    -- select * from fnc_appointment_list_dow_by_id(1);
    

    查询返回的约会日期数组:

    create or replace function fnc_appointment_array_dow_by_id(_app_id int)
            returns table (__app_id int, __title varchar, __recurrence_start_date timestamptz, __recurrence_appointment_day timestamptz[], __reccurence_dow_offset int[]) as
        $body$
            select
                    app.app_id,
                    app.app_title,
                    app.app_recurrence_start_date,
                    array_agg(_day::timestamptz),
                    array_agg(extract(dow from _day)::int)
                from
                    appointments app,
                    generate_series(app.app_recurrence_start_date, app.app_recurrence_end_date, interval '1 day') as _appointment_days(_day)
                where app.app_id=_app_id
                group by app.app_id, app.app_title, app.app_recurrence_start_date;
        $body$
            language sql stable; -- consider changing function volatility as needed.
    
    -- select * from fnc_appointment_array_dow_by_id(1);
    

    如果您正在寻找其中任何一个功能,请告诉我,我们可以继续下一个目标。

    参考文献

    【讨论】:

    • 非常感谢您提供如此有用的回复。这实际上让我到达了我需要的地方,尽管 - 我认为 - 它有点避开了我拥有的数组枚举列。我需要做的第一件事是为每个活动取消嵌套 {Monday,Tuesday,Thursday,Sunday,Saturday,Friday,Wednesday}。一旦我有了这个,我就可以使用你提到的概念,比如 extract 和 generate_series 来生成重复。
    • 很高兴你知道了。干杯。
    猜你喜欢
    • 2013-06-18
    • 2021-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-12
    • 2020-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多