【问题标题】:How to create sequence which start from 1 in each day如何创建每天从 1 开始的序列
【发布时间】:2016-06-01 07:48:15
【问题描述】:

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

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

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

使用 Postgres 9.1。

【问题讨论】:

  • 您可以安排一个作业来重置序列。或者,如果这是表中的一列,那么您可以在输出中计算它。
  • 也许可以创建 plpgsql 过程来检查当天的第一次调用并重置序列。如何在此期间加锁,以便对这个方法的并发调用被序列化?

标签: sql postgresql plpgsql postgresql-9.1


【解决方案1】:

使用表格保持顺序:

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;

【讨论】:

    【解决方案2】:

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

    用于运行 cron 作业的 Shell 命令 psql --host host.domain.com --port 32098 --db_name databaseName

    然后您可以将其添加到您的 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
    

    【讨论】:

      【解决方案3】:

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

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

      -- 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

      希望对您有所帮助。

      【讨论】:

      • 非常漂亮和干净:)
      【解决方案4】:

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

      处理来自查询的逻辑而不是修改序列。 如果它是当天表的第一个条目,则使用 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;
      

      【讨论】:

        猜你喜欢
        • 2015-11-27
        • 2019-07-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-04
        • 2021-10-02
        • 1970-01-01
        相关资源
        最近更新 更多