【问题标题】:postgresql company id based sequence基于postgresql公司ID的序列
【发布时间】:2011-01-12 18:42:33
【问题描述】:

我有一个包含公司及其产品的数据库,我想要每个 公司拥有单独的产品 ID 序列。

我知道postgresql不能做到这一点,唯一的办法就是为每家公司设置一个单独的序列,但这很麻烦。

我想了一个解决方案,有一个单独的表来保存序列

CREATE TABLE "sequence"
(
  "table" character varying(25),
  company_id integer DEFAULT 0,
  "value" integer
)

"table" 将保留序列的表名,例如产品、类别等。

并且 value 将保存将用于插入时 product_id 的实际序列数据

我将使用 UPDATE ... RETURNING 值;获取产品ID

我想知道这个解决方案是否有效?

使用行级锁定,只有同一公司的用户在同一个表中添加行将不得不等待获得锁定,我认为这减少了竞争条件问题。

有没有更好的方法来解决这个问题?

我不想为所有公司的产品表使用序列,因为产品 id 之间的差异会很大,我想让用户保持简单。

【问题讨论】:

    标签: postgresql insert conditional-statements sequence race-condition


    【解决方案1】:

    您可以在您的公司表中嵌入一个计数器:

    CREATE TABLE companies (
        id          SERIAL PRIMARY KEY,
        name        TEXT,
        product_id  INT DEFAULT 0
    );
    
    CREATE TABLE products (
        company     INT REFERENCES companies(id),
        product_id  INT,
        PRIMARY KEY (company, product_id),
    
        name        TEXT
    );
    
    INSERT INTO companies (id, name) VALUES (1, 'Acme Corporation');
    INSERT INTO companies (id, name) VALUES (2, 'Umbrella Corporation');
    

    然后,使用 UPDATE ... RETURNING 获取给定公司的下一个产品 ID:

    > INSERT INTO products VALUES (1, (UPDATE companies SET product_id = product_id+1 WHERE id=$1 RETURNING product_id), 'Anvil');
    ERROR:  syntax error at or near "companies"
    LINE 1: INSERT INTO products VALUES (1, (UPDATE companies SET produc...
                                                ^
    

    哦,不!看来您不能(从 PostgreSQL 9.1devel 开始)使用 UPDATE ... RETURNING 作为子查询。

    好消息是,这不是问题!只需创建一个执行增量/返回部分的存储过程:

    CREATE FUNCTION next_product_id(company INT) RETURNS INT
    AS $$
        UPDATE companies SET product_id = product_id+1 WHERE id=$1 RETURNING product_id
    $$ LANGUAGE 'sql';
    

    现在插入是小菜一碟:

    INSERT INTO products VALUES (1, next_product_id(1), 'Anvil');
    INSERT INTO products VALUES (1, next_product_id(1), 'Dynamite');
    INSERT INTO products VALUES (2, next_product_id(2), 'Umbrella');
    INSERT INTO products VALUES (1, next_product_id(1), 'Explosive tennis balls');
    

    确保在产品值和 next_product_id(company INT) 的参数中使用相同的公司 ID。

    【讨论】:

    • 请注意,这不是(据我所知)原子:company.product_id 可能会在没有相应插入产品的情况下增加。
    • 另外,在当前版本的 PostgreSQL 中可能不需要存储过程。
    【解决方案2】:

    根据您拥有的公司数量,您可以为每个公司创建一个序列。通过在您的 product_id 列上设置为默认值的函数查询它。

    或者,此函数可以简单地执行 SELECT FOR UPDATE 并更新表的值。我认为应该相当出色。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-12
      • 2011-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多