【问题标题】:Is it possible to refer a column in a view as foreign key (PostgreSQL 9.4)?是否可以将视图中的列引用为外键(PostgreSQL 9.4)?
【发布时间】:2016-04-02 15:29:15
【问题描述】:

我知道在旧版本中这是不可能的,9.4版本是否相同?

我正在尝试做这样的事情:

CREATE VIEW products AS 
    SELECT d1.id AS id, d1.price AS pr FROM dup.freshProducts AS d1
    UNION
    SELECT d2.id AS id, d2.price AS pr FROM dup.cannedProducts AS d2;

CREATE TABLE orderLines
( 
    line_id integer PRIMARY KEY, 
    product_no integer REFERENCES productView.id
);

我正在尝试实现freshProductscannedProducts 都继承自products 的继承关系。我使用两个不同的表实现了它,并创建了一个视图products,它只有freshProductscannedProducts 之间的公共属性。此外,orderLines 中的每一行都与productfreshProductcannedProduct 有关系。请参阅图片进行说明。

如果还不能引用视图,您认为哪种解决方案最好?我想到了物化视图或使用触发器实现限制。您能否推荐任何此类触发器的好示例作为基础?

非常感谢!

【问题讨论】:

    标签: postgresql postgresql-9.4


    【解决方案1】:

    防止 ID 重复的简单方法是在freshProducts 和cannedProducts 中使用与ID 默认值相同的序列。

    现在,问题来了,为什么需要外键?通常这是为了防止删除另一个表所依赖的数据,但是,您可以编写一个触发器来防止这种情况。此外,您已经将该值更新为 keyed-to 表中不存在的值,但您也可以为此编写触发器。

    因此,基本上您可以编写触发器来实现外键的所有所需功能,而实际上不需要外键,另外还有一个好处是它们将与这样的视图一起使用。

    【讨论】:

      【解决方案2】:

      引用(物化)视图不起作用,触发器可能如下所示:

      CREATE OR REPLACE FUNCTION reject_not_existing_id()
          RETURNS "trigger" AS
          $BODY$
              BEGIN
                  IF NEW.product_no NOT IN (SELECT id FROM dup.freshProducts UNION SELECT id FROM dup.cannedProducts) THEN
                      RAISE EXCEPTION 'The product id % does not exist', NEW.product_no;
                  END IF;
                  RETURN NEW;
              END;
          $BODY$
              LANGUAGE 'plpgsql' VOLATILE;
      
      CREATE TRIGGER tr_before_insert_or_update
          BEFORE INSERT OR UPDATE OF product_no
          ON orderLines
          FOR EACH ROW
          EXECUTE PROCEDURE reject_not_existing_id();
      

      (另见http://www.tek-tips.com/viewthread.cfm?qid=1116256

      物化视图可能看起来不错,但失败的原因有两个: 就像视图一样,您根本无法引用它,因为它不是表(继续尝试)。假设您可以,仍然存在防止freshProductscannedProducts 中的两个相同ID 的问题。是的,您可以在物化视图上定义一个 UNIQUE INDEX,但是如何确保在新鲜和罐头中都不会首先使用相同的 id? 如果使用orderLines 中的触发器,这仍然是您必须解决的问题。

      这让我建议重新考虑您的模型。 'Fresh' 和 'canned' 也可能是单个表 products 的属性值,因此所有麻烦都是多余的。如果新鲜和罐装产品的属性(数量)显着不同(想不出任何其他原因来创建两个不同的表),则在另外两个表中引用产品 ID。喜欢

      CREATE TABLE products
      (
          id ... PRIMARY KEY
          , fresh_or_canned ...
          , price ...
          , another_common_attribute_1 ...
          , ...
          , another_common_attribute_n ...
      );
      
      CREATE TABLE canned_specific_data
      (
          canned_id ... REFERENCES products (id)
          , type_of_can ...
          , ...
          , another_attribute_that_does_not_apply_to_fresh ...
      );
      
      CREATE TABLE fresh_specific_data
      (
          fresh_id ... REFERENCES products (id)
          , date_of_harvest ...
          , ...
          , another_attribute_that_does_not_apply_to_canned ...
      );
      

      【讨论】:

      • 非常感谢。我认为我会重新考虑如何实现我的模型。总而言之,这是最灵活的选择。
      猜你喜欢
      • 2023-03-30
      • 2018-10-26
      • 1970-01-01
      • 2011-03-05
      • 2010-10-01
      • 1970-01-01
      • 2017-06-10
      • 1970-01-01
      • 2015-03-28
      相关资源
      最近更新 更多