Par exemple, avec un tableau similaire à celui-ci:
create table foo(bar int identity, chk char(1) check (chk in('Y', 'N')));
Peu importe que le drapeau soit implémenté en tant que char(1)
, a bit
ou autre. Je veux juste pouvoir appliquer la contrainte selon laquelle elle ne peut être définie que sur une seule ligne.
constraint
database-agnostic
referential-integrity
Jack Douglas
la source
la source
Réponses:
SQL Server 2008 - Index unique filtré
la source
SQL Server 2000, 2005:
Vous pouvez profiter du fait qu'un seul null est autorisé dans un index unique:
pour 2000, vous pourriez avoir besoin
SET ARITHABORT ON
(merci à @gbn pour cette info)la source
Oracle:
Comme Oracle n'indexe pas les entrées où toutes les colonnes indexées sont nulles, vous pouvez utiliser un index unique basé sur une fonction:
Cet index n'indexera jamais qu'une seule ligne au maximum.
Connaissant ce fait d'index, vous pouvez également implémenter la colonne de bits légèrement différemment:
Ici, les valeurs possibles pour la colonne
chk
serontY
etNULL
. Une seule ligne au maximum peut avoir la valeurY.
la source
not null
contrainte?not null
contrainte si vous ne voulez pas de null (ce n'était pas clair pour moi d'après les spécifications de la question). Une seule ligne peut avoir la valeur «Y» dans tous les cas.default
)?Y
ounull
, voir ma mise à jour.null
s sont ignorés - au prix d'une certaine clarté peutJe pense qu'il s'agit de structurer correctement vos tables de base de données. Pour le rendre plus concret, si vous avez une personne avec plusieurs adresses et que vous en voulez une par défaut, je pense que vous devriez stocker l'ID d'adresse de l'adresse par défaut dans la table des personnes, pas avoir une colonne par défaut dans la table des adresses:
Vous pouvez rendre le DefaultAddressID nullable, mais de cette façon, la structure applique votre contrainte.
la source
MySQL:
Les contraintes de vérification sont ignorées dans MySQL, nous devons donc considérer
null
oufalse
comme faux ettrue
comme vrai. 1 ligne au maximum peut avoirchk=true
Vous pouvez considérer une amélioration d'ajouter un élément déclencheur de changement
false
danstrue
le insert / mise à jour comme une solution de contournement pour l'absence d'une contrainte de vérification - l' OMI ne constitue pas une amélioration bien.J'espérais pouvoir utiliser un char (0) car il
Malheureusement, avec MyISAM et InnoDB au moins, je reçois
--modifier
ce n'est pas une bonne solution après tout, car sur MySQL,
boolean
est synonyme detinyint(1)
, et autorise donc des valeurs non nulles à 0 ou 1. Il est possible quebit
ce soit un meilleur choixla source
null
,false
,true
- je me demande s'il y a quelque chose de plus propre ...Serveur SQL:
Comment faire:
La meilleure façon est un index filtré. Utilise DRI
SQL Server 2008+
Colonne calculée avec unicité. Utilise DRI
Voir la réponse de Jack Douglas. SQL Server 2005 et versions antérieures
Une vue indexée / matérialisée qui est comme un index filtré. Utilise DRI
Toutes les versions.
Déclencheur. Utilise le code, pas DRI.
Toutes les versions
Comment ne pas le faire:
Voir un deux trois quatre
la source
PostgreSQL:
--modifier
ou (beaucoup mieux), utilisez un index partiel unique :
la source
Ce genre de problème est une autre raison pour laquelle j'ai posé cette question:
Paramètres d'application dans la base de données
Si vous avez une table de paramètres d'application dans votre base de données, vous pourriez avoir une entrée qui ferait référence à l'ID de l'enregistrement que vous souhaitez considérer comme «spécial». Ensuite, il vous suffit de rechercher l'ID dans votre tableau de paramètres, de cette façon, vous n'avez pas besoin d'une colonne entière pour un seul élément en cours de définition.
la source
Approches possibles utilisant des technologies largement mises en œuvre:
1) Révoquer les privilèges «écrivain» sur la table. Créez des procédures CRUD qui garantissent que la contrainte est appliquée aux limites des transactions.
2) 6NF: déposez la
CHAR(1)
colonne. Ajoutez une table de référencement contrainte pour garantir que sa cardinalité ne peut pas dépasser une:Modifiez la sémantique de l'application afin que la valeur par défaut considérée soit la ligne de la nouvelle table. Utilisez éventuellement des vues pour encapsuler cette logique.
3) Déposez la
CHAR(1)
colonne. Ajoutez uneseq
colonne entière. Mettez une contrainte uniqueseq
. Modifiez la sémantique de l'application de sorte que la valeur par défaut considérée soit la ligne où laseq
valeur est égale à un ou laseq
valeur la plus grande / la plus petite ou similaire. Utilisez éventuellement des vues pour encapsuler cette logique.la source
Pour ceux qui utilisent MySQL, voici une procédure stockée appropriée:
Pour vous assurer que votre table est propre et que la procédure stockée fonctionne, en supposant que l'ID 200 est la valeur par défaut, exécutez ces étapes:
Voici un déclencheur qui aide également:
Pour vous assurer que votre table est propre et que le déclencheur fonctionne, en supposant que l'ID 200 est la valeur par défaut, exécutez ces étapes:
Essaie !!!
la source
Dans SQL Server 2000 et versions ultérieures, vous pouvez utiliser des vues indexées pour implémenter des contraintes complexes (ou multi-tables) comme celle que vous demandez.
Oracle a également une implémentation similaire pour les vues matérialisées avec des contraintes de vérification différées.
Voir mon article ici .
la source
Standard Transitional SQL-92, largement implémenté, par exemple SQL Server 2000 et supérieur:
Révoquer les privilèges «écrivain» de la table. Créez deux vues pour
WHERE chk = 'Y'
etWHERE chk = 'N'
respectivement, y comprisWITH CHECK OPTION
. Pour laWHERE chk = 'Y'
vue, incluez une condition de recherche selon laquelle sa cardinalité ne peut pas dépasser une. Accordez des privilèges «d'écrivain» sur les vues.Exemple de code pour les vues:
la source
Voici une solution pour MySQL et MariaDB utilisant des colonnes virtuelles qui est un peu plus élégante. Il nécessite MySQL> = 5.7.6 ou MariaDB> = 5.2:
Créez une colonne virtuelle NULL si vous ne souhaitez pas appliquer la contrainte Unique:
(Pour MySQL, utilisez
STORED
plutôt quePERSISTENT
.)la source
Standard FULL SQL-92: utilisez une sous-requête dans une
CHECK
contrainte, pas largement implémentée, par exemple prise en charge dans Access2000 (ACE2007, Jet 4.0, peu importe) et au-dessus en mode de requête ANSI-92 .Exemple de code: les
CHECK
contraintes de note dans Access sont toujours au niveau de la table. Étant donné que l'CREATE TABLE
instruction dans la question utilise uneCHECK
contrainte au niveau de la ligne , elle doit être légèrement modifiée en ajoutant une virgule:la source
Je n'ai fait qu'effleurer les réponses, alors j'ai peut-être manqué une réponse similaire. L'idée est d'utiliser une colonne générée qui est soit le pk ou une constante qui n'existe pas comme valeur pour le pk
AFAIK c'est valable dans SQL2003 (puisque vous cherchiez une solution agnostique). DB2 le permet, sans savoir combien d'autres fournisseurs l'acceptent.
la source