2017-09-02 3 views
0

J'ai deux tables product et tag avec une table de jonction products_tags. Un produit peut avoir plusieurs étiquettes différentes, et une étiquette peut avoir plusieurs produits différents, mais la relation entre un produit et une étiquette doit être unique.Mise à jour de la table de jonction

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) 
) 

Je planifie actuellement de mettre à jour la table de jonction en envoyant un tableau tags avec l'objet produit à chaque fois qu'il est mis à jour par la couche frontend, supprimez toutes les lignes products_tags qui contiennent le product_id en cours et créer une nouvelle ligne dans products_tags pour chaque ID dans le tableau tags.

Ma question est la suivante: y a-t-il un moyen plus efficace d'y parvenir? Ou est-ce que la suppression et la réinsertion des lignes sont la seule façon de garantir l'intégrité des données dans une table de jonction?

+0

Cela entraînera la création d'un trop grand nombre de versions de lignes, même lorsque les modifications sont minimes (ce qui pourrait coûter 2 * N lignes affectées!). Mieux insérer ce qui n'est pas dans la table DB + supprimer ce qui ne figure pas dans la nouvelle liste; – wildplasser

+0

Vous avez raison @wildplasser Je pense que je vais créer une fonction postgres pour gérer cela, le faire dans le calque de l'application, c'est comme si cela causerait trop de roundtrips à la base de données et peut-être désordre. – Toni

+0

La fonction n'est pas nécessaire ici. Vous pouvez utiliser un CTE chaîné pour combiner les deux opérations. Et peut-être le mettre dans une déclaration préparée. – wildplasser

Répondre

1

Pour ceux qui pourraient être aux prises avec cela, c'est ce que j'ai fini avec. Probablement encore peut être optimisé, mais certainement une bien meilleure solution que celle de ma question initiale.

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 

Big tnks à @wildplasser pour moi pointant dans la bonne direction!