2017-09-02 41 views
0

我有两个表producttag与联结表products_tags。一个产品可以有多个不同的标签,一个标签可以有很多不同的产品,但是一个产品和一个标签之间的关系需要是唯一的。更新交界表

CREATE TABLE product (
    id serial PRIMARY KEY NOT NULL, 
    name varchar(255) NOT NULL 
) 

CREATE TABLE tag (
    id serial PRIMARY KEY NOT NULL, 
    name varchar(255) NOT NULL 
) 

CREATE TABLE products_tags (
    product_id integer NOT NULL REFERENCES product(id), 
    tag_id integer NOT NULL REFERENCES tag(id), 
    PRIMARY KEY(product_id, tag_id) 
) 

目前,我计划在每次由前端层更新时间发送tags阵列Product对象更新联接表,删除products_tags包含当前product_id所有行,并创建一个新的行对于tags阵列中的每个ID,在products_tags中。

我的问题是:是否有更高效的方法来实现这一目标?或者是删除并重新插入行是确保联结表中数据完整性的唯一方法?

+0

这会导致创建太多的行版本,即使这些更改很少(可能会损失2 * N个受影响的行!)。更好地插入不在数据库表中的内容+删除不在新列表中的内容; – wildplasser

+0

你是对的@wildplasser我想我会创建一个postgres函数来处理这个问题,在应用程序层中这样做会感觉它会导致太多的往返数据库,并可能会变得混乱。 – Toni

+0

这里不需要函数。您可以使用链式CTE来组合这两个操作。也许把它放在一个准备好的声明中。 – wildplasser

回答

1

对于任何可能为此而挣扎的人,这就是我最终的结果。可能仍然可以进行优化,但绝对是比我最初的问题更好的解决方案。

WITH insert_new_tags AS (
    INSERT INTO products_tags (product_id, tag_id) 
     VALUES (2, 1), (2, 2), (2, 7) 
     ON CONFLICT (product_id, tag_id) 
     DO NOTHING 
    RETURNING * 
), 
delete_missing_tags AS (
    DELETE FROM products_tags 
    WHERE product_id = 2 AND tag_id NOT IN (1, 2, 7) 
    RETURNING * 
) 

SELECT *, 'inserted' AS operation FROM insert_new_tags 
UNION 
SELECT *, 'deleted' AS operation FROM delete_missing_tags 

给@wildplasser的大忙会让我指向正确的方向!