【问题标题】:Postgres unique combination constraint across tablesPostgres 跨表的唯一组合约束
【发布时间】:2014-07-23 12:08:07
【问题描述】:

我有三张桌子 -

file (
  file_id int primary key
  filename text not null
  etc...
)
product (
  product_id int primary key
  etc....
)
product_attachment (
  product_id references product
  file_id references file
)

我想确保当这些是自然连接时,product_id + 文件名是唯一的。 到目前为止,我最好的解决方案是将文件名添加到 product_attachment 表中,但我想知道是否有办法避免这种情况。

【问题讨论】:

    标签: sql postgresql foreign-keys unique-constraint


    【解决方案1】:

    如果文件名列不是唯一的,您可以在product_attachment 表上添加自定义约束。请注意,这将在每次插入和更新时执行下面的查询,这在性能方面并不理想。

    CREATE OR REPLACE FUNCTION check_filename(product_id integer, file_id integer)
    RETURNS boolean AS
    $$
        LOCK product_attachment IN SHARE MODE;
        SELECT (COUNT(*) = 0)
        FROM product_attachment pa
        JOIN file f1 ON f1.file_id = pa.file_id
        JOIN file f2 ON f1.filename = f2.filename
        WHERE pa.product_id = $1 AND f2.file_id = $2
    $$
    LANGUAGE 'plpgsql'
    
    ALTER TABLE product_attachment
    ADD CONSTRAINT check_filename CHECK
    (check_filename(product_id, file_id))
    

    【讨论】:

    • 我不清楚为什么你有一个“for update”,我认为测试应该是 count(*) = 0 (或者使用带有“exists”的子查询可能会更好性能),但这正是我正在寻找的方法,谢谢!
    • @qcodepeter 你是对的,应该是count(*) = 0for update 锁定选定的行以防止竞争条件
    • 如果我理解正确,查询将锁定并返回 0 行——在这种情况下,锁什么也不做——或者约束将失败——在这种情况下,锁什么也不做。也许在查询的开头添加“lock product_attachment in share mode”可以解决问题?
    • @qcodepeter 如果我理解the docsfor update 获得表级锁定,但正如您所提到的那样显式锁定表可能更清晰、更安全。顺便说一句,如果可以更新 filename 您可能需要对您的 file 表进行类似的约束
    • 您说它获得了表级锁是对的,但它只是一个row share 锁,我认为这还不够。碰巧的是,我们目前不允许 filename 更新,所以我不会担心,但是是的,否则这将是一个考虑因素。
    【解决方案2】:

    为什么不给product_attachment添加一个唯一的约束?

    create unique index idx_product_attachment_2 on product_attachment(product_id, file_id);
    

    这假定文件名是唯一的,您可以通过将文件名定义为该表中的唯一性来确保这一点。

    【讨论】:

    • 文件名在整个文件表中不是唯一的,不幸的是这是系统的要求。
    猜你喜欢
    • 1970-01-01
    • 2015-03-06
    • 1970-01-01
    • 2012-05-07
    • 1970-01-01
    • 2017-07-07
    • 1970-01-01
    • 1970-01-01
    • 2012-05-17
    相关资源
    最近更新 更多