【问题标题】:Generate an account number with sequence生成带序列的帐号
【发布时间】:2022-01-29 04:45:14
【问题描述】:

我有一个需求,我需要生成一个帐号并将其插入到以下格式的表格列中。 “TBA2222011300000001” = 其中“TBA”是另一列的值或用户发送的数据,“22220113”表示当前日期,“00000001”是一个七位数的序列,每次插入都需要递增和附加。

如何将序列附加到列中,我应该在 java 中执行还是在 DB 端执行。我目前正在使用带有 java 和 spring boot 的 postgres。

【问题讨论】:

  • “用户发送数据”?那么前缀可能会在运行时发生变化?
  • "七位数字序列" — 这是每个前缀+日期的序列吗?所以在 30 号我们有一个 TBA2222011300000001 值,在第二天 31 号我们将有一个 TBA2222011310000001 值?
  • 每次插入数据库时​​,序列都会递增,例如:00000001、00000002 等。没有在 30 日我们将有“TBA2222013000000001”

标签: java postgresql spring-boot


【解决方案1】:

https://www.postgresql.org/docs/current/ddl-generated-columns.html

生成的列是一个特殊的列,总是从 其他栏目。
几个限制适用于定义 生成的列和涉及生成列的表:

  • 生成表达式只能使用不可变函数,不能使用子查询或引用当前行以外的任何内容 以任何方式。

now() 是可变函数,所以不能使用Generated columns。 我不知道为什么Default 不起作用。
https://www.postgresql.org/docs/current/ddl-default.html 所以现在唯一的选择就是触发。

CREATE TABLE account_info(
    account_id INT GENERATED ALWAYS AS IDENTITY,
    account_type text not null,
    acconut_number text ) ;

所以你想要的是自动化:

UPDATE account_info set 
    account_number = 
    concat(
        account_type,
        to_char(CURRENT_DATE, 'yyyymmdd'),
        to_char(account_id, 'FM00000000'));

创建函数

create or replace function update_account_number() returns trigger as $$
BEGIN
UPDATE account_info set 
    account_number = 
    concat(
        account_type,
        to_char(CURRENT_DATE, 'yyyymmdd'),
        to_char(account_id, 'FM00000000'));
RETURN NULL; 
end;
$$  LANGUAGE plpgSQL;

创建触发器:

CREATE OR REPLACE TRIGGER udpate_accout_number
    AFTER INSERT ON account_info
    FOR EACH ROW
    EXECUTE FUNCTION update_account_number();

【讨论】:

  • 这里出现的唯一问题,DB 中的触发器成本高吗?
  • @PragmaticFire 我不确定。另一种选择是将日期存储在一列中,这样您就可以轻松地连接 3 列。
【解决方案2】:

有一个 id 列,它是 postgres 中的标识,并根据需要具有开始和结束索引。 供您参考根据需要创建标识列 https://www.postgresqltutorial.com/postgresql-identity-column/

还有 1 列用于 createdDate。

那么帐号只是一个派生值 TBA + formatted(DATE) + formatted(Id)。 前任 - 不,不是触发器,只是一个功能。您的表格中不会有任何帐号列。它只是一个将日期和身份作为输入并给出帐号作为输出的函数。由于帐号仅取决于 ID 和日期。根本不需要存储这个值,只要你需要账号就调用那个函数。帐号根本不存在。它将始终根据 id 和 date 计算。很简单。

在文章中参考这个 方法一:派生值称为“标记”

我们可能要添加到此表的第一个方法是 accountNumber 方法,用于根据当前日期和 id 计算我们的 accountNumber。由于该值将始终基于其他两个存储值,因此存储它是没有意义的(可能存储在预先计算的索引中除外)。为此,我们:

CREATE FUNCTION accountNumber(id,date) RETURNS varchar AS
$$ SELECT TBA + format(id) + format(date)
$$ LANGUAGE SQL IMMUTABLE; 

您需要根据您的要求为 format(id) 和 format(date) 设置逻辑。

没有必要存储可以从其他 2 列轻松导出的值。这将不必要地消耗空间。维护数据完整性和检查也是一项开销。

为派生值创建函数 https://ledgersmbdev.blogspot.com/2012/08/postgresql-or-modelling-part-2-intro-to.html

您可以在输出和搜索中使用该功能。 索引也将根据需要使用。

【讨论】:

  • 所以你想让我在每次插入后在数据库中添加一个触发器以附加“TBA 日期和序列”并更新列值?我已经在表中有一个序列列,我怀疑我们是否需要另一个列来增加。我还编辑了 TBA 可能并不总是恒定但很少见的问题。
  • 我已经编辑了答案。另请参考本文中的ledgersmbdev.blogspot.com/2012/08/… 方法一。它解释清楚,不需要触发器或任何其他列。只需该功能即可完成工作。没有任何开销
【解决方案3】:

我执行以下操作来生成所需的帐号。

  1. 创建了一个新序列并为其添加了零。

select to_char(nextval('finance_accounts_id_seq'), 'fm00000000')

  1. 使用 DateTimeFormatter 在 java 中获取当前日期

    DateTimeFormatter dmf = DateTimeFormatter.ofPattern("yyyyMMdd"); 字符串日期 = LocalDate.now().format(dmf);

  2. 从用户的请求参数中获得“TBA”。

【讨论】:

    猜你喜欢
    • 2010-12-29
    • 2012-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-29
    • 1970-01-01
    • 2011-08-25
    • 1970-01-01
    相关资源
    最近更新 更多