2010-04-20 39 views
1

"one-to-many" Pour illustrer le problème, je fais un exemple:contrainte unique (w/o Trigger) sur la relation

Un tag_bundle se compose d'un ou plusieurs d'un balises. Une combinaison de balises unique peut correspondre à un tag_bundle unique, et inversement.

tag_bundle     tag   tag_bundle_relation 
+---------------+  +--------+  +---------------+--------+ 
| tag_bundle_id |  | tag_id |  | tag_bundle_id | tag_id | 
+---------------+  +--------+  +---------------+--------+ 
|  1  |  | 100 |  |  1  | 100 | 
+---------------+  +--------+  +---------------+--------+ 
|  2  |  | 101 |  |  1  | 101 | 
+---------------+  +--------+  +---------------+--------+ 
          | 102 |  |  2  | 101 | 
          +--------+  +---------------+--------+ 
              |  2  | 102 | 
              +---------------+--------+ 

Il ne peut y avoir une autre tag_bundle ayant exactement la même combinaison de l'étiquette 100 et étiquette 101. Il ne peut y avoir une autre tag_bundle ayant exactement la même combinaison de l'étiquette 101 et étiquette 102.

Comment puis-je assurer cette contrainte unique lors de l'exécution de SQL "simultanément" !! qui est, en même temps pour éviter ajoutant deux faisceaux exactement la même combinaison

tag Ajout d'une simple contrainte unique sur une table ne fonctionne pas, Y at-il d'autre solution que de déclenchement ou de verrouillage explicite.

Je viens seulement de cette façon simple: faire une combinaison de balises en chaîne, et que ce soit une colonne unique.

tag_bundle (unique on tags)   tag   tag_bundle_relation 
+---------------+-----------+  +--------+  +---------------+--------+ 
| tag_bundle_id | tags  |  | tag_id |  | tag_bundle_id | tag_id | 
+---------------+-----------+  +--------+  +---------------+--------+ 
|  1  | "100,101" |  | 101 |  |  1  | 101 | 
+---------------+-----------+  +--------+  +---------------+--------+ 
            | 100 |  |  1  | 100 | 
            +--------+  +---------------+--------+ 

mais il ne semble pas une bonne façon :(

+0

Voulez-vous autoriser un tab_id à participer à plusieurs bundles? Par exemple, 'tag_bundle_id = 2' a' tags = (100, 200) '? Qu'en est-il des super-ensembles/sous-ensembles, 'tag_bundle_id = 3 aurait-il des balises (100, 101, 102)'? –

+0

tag_bundle_id = 2 avec les tags = (100, 200) est autorisé, tag_bundle_id = 3 a tags (100, 101, 102) est également autorisé. – elgcom

+0

Alors, oui ou non sur les sous-ensembles? – MkV

Répondre

1

Pourquoi la contrainte de «sans un élément déclencheur? Avec elle, combinée avec un peu de duplication de données, vous pouvez obtenir ce dont vous avez besoin. Changez champ 'tags' dans votre solution à un champ de tableau INTEGERs (ou quel que soit le type tag_id est)

Tout en reconnaissant le désagrément de la solution, je ne vois pas un moyen de contourner ce problème. une chaîne pour 'tags', mettez-la dans une table séparée de tag_bundle, la rendez toujours unique et mettez un trigger sur tag_bundle_relation pour mettre à jour le champ tags avec array_agg (t ag_id) (> 8.4), et si cela échoue, la mise à jour du trigger échoue.

-1

Afin de fonctionner correctement lorsque plusieurs transactions seront mises à jour les tables, vous devrez créer un différentiel, initialement différé, constraint trigger.

+1

Corrigez-moi si je me trompe, mais - à moins de sérialiser l'appel de fonction - un déclencheur ne vous sauvera pas des conditions de course, car les modifications effectuées par d'autres transactions en parallèle ne sont pas visibles. Un déclencheur de contrainte * différée * réduit * la fenêtre d'opportunité pour les conditions de course, mais il est toujours possible que deux de ces déclencheurs fonctionnent en parallèle, sans voir les données des uns et des autres (encore non-validées). – intgr

+0

@intgr excellente question. Je ne connais pas la réponse. J'ai supposé que les transactions de transaction étaient sérialisées, et que par conséquent le traitement des fonctions de déclenchement était reporté au moment où la transaction était validée. Peut-être Serializable niveau d'isolement est nécessaire pour garantir cela. Si la décision d'autoriser ou non une mise à jour dépend du fait que d'autres transactions concurrentes sont validées ou annulées, cet autre commit ou rollback doit se terminer en premier, avec ses déclencheurs différés. –