如何创建每天从1开始的序列

问题描述 投票:0回答:5

序列应返回值 1、2、3 等,每天从 1 开始。 current_date 应用于确定日期。

例如,今天第一次调用应返回 1,第二次调用应返回 2 等

明天,第一次调用应再次返回 1,第二次调用应返回 2 等等

使用Postgres 9.1。

sql postgresql plpgsql postgresql-9.1
5个回答
3
投票

使用表格来保存顺序:

create table daily_sequence (
    day date, s integer, primary key (day, s)
);

此函数将检索下一个值:

create or replace function daily_sequence()
returns int as $$
    insert into daily_sequence (day, s)
    select current_date, coalesce(max(s), 0) + 1
    from daily_sequence
    where day = current_date
    returning s
    ;
$$ language sql;

select daily_sequence();

准备好重试,以防出现不太可能的

duplicate key value
错误。如果不需要前几天的序列,请删除它们以使表格和索引尽可能轻:

create or replace function daily_sequence()
returns int as $$
    with d as (
        delete from daily_sequence
        where day < current_date
    )
    insert into daily_sequence (day, s)
    select current_date, coalesce(max(s), 0) + 1
    from daily_sequence
    where day = current_date
    returning s
    ;
$$ language sql;

1
投票

您只需将 cronjob 视为在指定时间或日期运行 shell 命令即可。

用于运行 cron 作业的 Shell 命令 psql --host host.domain.com --port 32098 --db_name 数据库名称 < my.sql

然后您可以将其添加到您的 crontab (我建议您使用 crontab -e 以避免破坏东西)

# It will run your command at 00:00 every day
# min hour wday month mday command-to-run
    0    0    *     *    * psql --host host.domain.com --port 32098 --db_name databaseName < my.sql

1
投票

这是一个非常有趣的任务。

让我们尝试使用日期的附加序列和替代函数来获取下一个值:

-- We will use anonymous block here because it is impossible to use
-- variables and functions in DDL directly 
do language plpgsql $$
begin
  execute 'create sequence my_seq_day start with ' || (current_date - '1900-01-01')::varchar;
end; $$;

-- Initialize sequence
select nextval('my_seq_day');

create sequence my_seq;

create or replace function nextval_daily(in p_seq varchar) returns bigint as $$
declare
  dd bigint;
  lv bigint;
begin
  select current_date - '1900-01-01'::date into dd;
  -- Here we should to retrieve current value from sequence
  -- properties instead of currval function to make it session-independent 
  execute 'select last_value from '||p_seq||'_day' into lv;
  if dd - lv > 0 then
    -- If next day has come
    -- Reset main sequens
    execute 'alter sequence '||p_seq||' restart';
    -- And set the day sequence to the current day
    execute 'alter sequence '||p_seq||'_day restart with '||dd::varchar;
    execute 'select nextval('''||p_seq||'_day'')' into lv;
  end if;
  return nextval(p_seq);
end; $$ language plpgsql;

然后使用函数

nextval_daily
而不是
nextval

希望对您有帮助。


0
投票

我遇到过几乎类似的要求。

处理查询中的逻辑而不是修改序列。 如果它是当天表中的第一个条目,则使用 setval() 将序列重置为 0。 否则序列的 nextval()

以下是示例查询:

SELECT
CASE WHEN NOT EXISTS (
SELECT   primary_key   FROM    schema.table   WHERE   date(updated_datetime) = #{systemDate} limit 1)
THEN 
setval('scheam.job_seq', 1) 
ELSE 
nextval('scheam.job_seq') 
END

UPDATE 用户需要有权限才能执行 setval。

GRANT UPDATE ON ALL SEQUENCES IN SCHEMA ur_schema TO user;

0
投票

我受到 Clodoaldo Neto 的回答的启发,并为我的项目编写了一个脚本。 您可以自己复制并立即使用,只是不要忘记更改与您的项目相关的名称和注释。

create sequence if not exists daily_sequence start 1 increment 1;
comment on sequence daily_sequence is 'The sequence which reset every day';

create table last_reset_date_table
(
    last_reset_date date not null
);

comment on table last_reset_date_table is 'The table keeps the last reset date of daily_sequence';

insert into last_reset_date_table (last_reset_date)
values (current_date);

comment on column last_reset_date_table.last_reset_date is 'The last reset date of daily_sequence';

create
    or replace function daily_sequence()
    returns integer as
$$
declare
    v_last_reset_date date;
begin
    -- Select the last reset date 'for the update' to lock the row
    select last_reset_date
    into v_last_reset_date
    from last_reset_date_table for update;

    -- Check if the last reset date is today
    if
            v_last_reset_date != current_date then
        -- Reset the sequence
        perform setval('daily_sequence', 1, false);
        -- Update the last reset date to today
        update last_reset_date_table
        set last_reset_date = current_date
        where last_reset_date != current_date;
    end if;
    return nextval('daily_sequence');
end;
$$
    language plpgsql;
© www.soinside.com 2019 - 2024. All rights reserved.