【问题标题】:How to disable same barcode for different producer codes如何为不同的生产者代码禁用相同的条形码
【发布时间】:2018-07-19 19:54:49
【问题描述】:

Postgres 9.1.2 数据库包含产品表

create table product (
ProductCode char(10) primary key,
ProducerCode char(15),
BarCode char(13) );

如何只允许相同的条形码用于相同的生产者代码。 例如这些值是有效的:

INSERT INto product values ('product1', '1', '1111111111111');
INSERT INto product values ('product2', '1', '1111111111111');

但此插入会导致错误,因为条形码 1111111111111 已在生产者代码 1 中使用

INSERT INto product values ('product3', '2', '1111111111111');

使用

“x86_64-unknown-linux-gnu 上的 PostgreSQL 9.1.2,由 gcc-4.4.real (Debian 4.4.5-8) 4.4.5 编译,64 位”

【问题讨论】:

    标签: sql postgresql constraints postgresql-9.1 unique-constraint


    【解决方案1】:

    你有错误的数据结构。你应该有两个表:

    create table product (
        ProductCode char(10) primary key,
        BarCode char(13)
    );
    
    create table BarCode (
        BarCode char(13) primary key,
        ProducerCode char(15)
    );
    

    这种结构会自动保证一个条码最多有一个ProducerCode

    注意:我建议不要使用字符串作为主键,而是使用 serial 列。 char() 特别奇怪,除非你确定列的长度是固定的。

    编辑:

    或者:

    create table product (
        ProductCode char(10) primary key,
        ProducerCode char(15)
    );
    
    create table ProducerCodes (
        ProducerCode char(15) primary key,
        BarCode char(13) primary key unique
    );
    

    这也应该做你想做的事。请注意,BarCode 可能是 NULL

    【讨论】:

    • 不幸的是,我无法使用 chage 数据库结构。如何使用有问题的表结构来实现这一点?
    • Answer 假定条形码始终存在。这是错误的。 BarCode 可以为 null,并且只能指定 ProducerCode。
    • 答案似乎没有做出这样的假设 - 如果条形码为空,那么表 BarCode 中将没有行。如果有条形码,那么它将被强制属于一个且只有一个生产者。
    • 更新的答案假定 ProducerCode 不为空。 ProducerCode 也可以为空。如果 BarCode 和 ProducerCode 都可能为空,如何使用这个答案?
    【解决方案2】:

    使用ProducerCode而不是输入的“条形码”将左侧填充字符串插入barcode

    代码看起来像

    INSERT INTO Product ( ProductCode , ProducerCode , BarCode ) 
    VALUES ('product1' , '1' , LPAD('1' , 13 , '0'))
    

    将为每个 ProducerCode 生成一个唯一的 Barcode

    结束数据如下所示

    ('product1' , '1' , '0000000000001');
    ('product2' , '1' , '0000000000001');
    ('product3' , '2' , '0000000000002');
    

    注意第 1 行和第 2 行中对应的ProducerCode 重复的Barcode

    【讨论】:

    • 此条码是针对生产者还是针对产品?我之前误会了独特性。
    • 我不明白你的回答。您能否提供使用来自答案的数据来实现此功能的示例代码?
    • 请稍等。
    • 没有。条码在店内分配,同一生产者代码相同。
    • INSERT INto product values ('product3', '2', '1111111111111'); 命令应该出现错误。如何实施?另外,条形码值应该是1111111111111,而不是你的答案
    【解决方案3】:

    如果不能更改数据库结构,请更改插入命令

    INSERT INTO product select 'product3', '2', '1111111111111' where '1111111111111' not in (select barcode from product) returning *
    

    然后检查返回的内容以确定插入是否成功

    【讨论】:

      【解决方案4】:

      如果您可以创建函数和触发器,请在 ON BEFORE INSERT 触发器中进行:

      CREATE FUNCTION error_on_barcode_at_another_producer()  RETURNS trigger
          VOLATILE
      AS $body$
      BEGIN
          IF EXISTS (
                  SELECT 1 FROM products p 
                  WHERE p.bar_code = NEW.bar_code AND p.producer_code <> NEW.producer_code) THEN
             RAISE EXCEPTION 'bar_code is already linked to another producer_code';
          END IF;
      
          RETURN NEW;
      END;
      $body$ LANGUAGE plpgsql
      
      CREATE TRIGGER tr_error_on_barcode_at_another_producer
          BEFORE INSERT OR UPDATE ON products
          FOR EACH ROW
      EXECUTE PROCEDURE error_on_barcode_at_another_producer()
      

      另一方面,您似乎没有机会对架构进行任何更改。然后你必须改变你的INSERT 声明。如果有要插入的bar_code 已应用于另一个producer_code,则此人查看products 表。如果该条件匹配,则b.* 不是NULL,因此它将被WHERE 子句过滤。如果没有这种情况,SELECT 会得到一个可以插入的结果。

      INSERT INTO products
      
      SELECT 
          a.* 
      FROM
          (SELECT 'product3' AS product_code, '2' AS producer_code, '1111111111111' AS bar_code) a --your values here
      LEFT JOIN products b
      ON a.bar_code = b.bar_code AND a.producer_code <> b.producer_code
      WHERE b.product_code IS NULL
      
      RETURNING *
      

      RETURNING 可以指示您是否存在冲突(没有返回行)或没有(返回插入的行)

      【讨论】:

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