2017-09-02 45 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的大忙會讓我指向正確的方向!