J'ai une colonne: standard BOOLEAN NOT NULL
Je voudrais appliquer une ligne True et toutes les autres False. Il n'y a pas de FK ou quoi que ce soit d'autre selon cette contrainte. Je sais que je peux l'accomplir avec plpgsql, mais cela ressemble à un marteau. Je préférerais quelque chose comme une contrainte CHECK
ou UNIQUE
. Plus c'est simple, mieux c'est.
Une ligne doit être True, elles ne peuvent pas toutes être False (donc la première ligne insérée doit être True).
La ligne devra être mise à jour, ce qui signifie que je dois attendre pour vérifier les contraintes jusqu'à ce que les mises à jour soient terminées, car toutes les lignes peuvent être définies sur False en premier et une ligne sur True après.
Il existe un FK entre products.tax_rate_id
et tax_rate.id
, mais cela n'a rien à voir avec le taux de taxe par défaut ou standard, qui est sélectionnable par l'utilisateur pour faciliter la création de nouveaux produits.
PostgreSQL 9.5 si cela est important.
Contexte
Le tableau est le taux d'imposition. L'un des taux de taxe est la valeur par défaut ( standard
car la valeur par défaut est une commande Postgres). Lorsqu'un nouveau produit est ajouté, le taux de taxe standard est appliqué au produit. S'il n'y en a pas standard
, la base de données doit faire une supposition ou toutes sortes de vérifications inutiles. La solution simple, je pensais, était de s'assurer qu'il y avait un standard
.
Par «par défaut» ci-dessus, je veux dire pour la couche de présentation (UI). Il existe une option utilisateur pour modifier le taux de taxe par défaut. Je dois soit ajouter des vérifications supplémentaires pour m'assurer que l'interface graphique / l'utilisateur n'essaie pas de définir tax_rate_id sur NULL, soit simplement définir un taux de taxe par défaut.
Réponses:
Variante 1
Puisque tout ce dont vous avez besoin est une seule colonne avec
standard = true
, définissez la norme sur NULL dans toutes les autres lignes. Ensuite, uneUNIQUE
contrainte simple fonctionne, car les valeurs NULL ne la violent pas:DEFAULT
est un rappel facultatif que la première ligne entrée doit devenir la valeur par défaut. Il n'applique rien. Bien que vous ne puissiez pas définir plusieurs lignes surstandard = true
, vous pouvez toujours définir toutes les lignes NULL. Il n'existe aucun moyen propre d'empêcher cela avec seulement des contraintes dans une seule table.CHECK
les contraintes ne prennent pas en compte les autres lignes (sans astuces sales).En relation:
Empêcher deux valeurs de colonne spécifiques d'exister en même temps
Ajouter une contrainte pour rendre la colonne unique par groupe de lignes
Mettre à jour:
Pour autoriser une commande comme (où la contrainte n'est satisfaite qu'à la fin de l'instruction):
.. la
UNIQUE
contrainte devrait êtreDEFERRABLE
. Voir:dbfiddle ici
Variante 2
Avoir une deuxième table avec une seule ligne comme:
Créez ceci en tant que superutilisateur:
Maintenant, il y a toujours une seule ligne pointant vers la norme (dans ce cas simple représentant également directement le taux standard). Seul un superutilisateur pouvait le casser. Vous pouvez également interdire cela avec un déclencheur
BEFORE DELETE
.dbfiddle ici
En relation:
Vous pouvez ajouter un
VIEW
pour voir la même chose que dans la variante 1 :Dans les requêtes où tout ce que vous voulez est le taux standard, utilisez (uniquement)
taxrate_standard.taxrate
directement.Vous avez ajouté plus tard:
La mise en œuvre d' un pauvre homme de la variante 2 serait d'ajouter simplement une ligne
products
(ou tout autre tableau similaire) pointant vers le taux d'imposition standard; un produit factice que vous pourriez appeler "Taux de taxe standard" - si votre configuration le permet.Les contraintes FK imposent l'intégrité référentielle. Pour le compléter, appliquez
tax_rate_id IS NOT NULL
pour la ligne (si ce n'est pas le cas pour la colonne en général). Et interdire sa suppression. Les deux pourraient être mis en déclencheurs. Pas de table supplémentaire, mais moins élégante et moins fiable.la source
CROSS JOIN
contre la norme,LEFT JOIN
la spécifique, puisCOALESCE
entre les deux.CONSTRAINT standard_only_1_true UNIQUE (standard)
: Je suppose que la table ne sera pas grande, donc cela n'a pas beaucoup d'importance, mais comme la contrainte définira un index sur toute la table, un index unique partiel avecWHERE (standard)
moins d'espace utilisera-t-il?Vous pouvez utiliser un index filtré
dbfiddle ici
Mais comme vous l'avez dit, la première ligne doit être vraie, alors vous pouvez utiliser une contrainte CHECK, mais même en utilisant une fonction, vous pouvez supprimer la première ligne plus tard.
dbfiddle ici
Vous pouvez le résoudre en ajoutant un déclencheur BEFORE DELETE pour vous assurer que la première ligne (foo est vrai) n'est jamais supprimée.
dbfiddle ici
la source