Je veux faire en sorte qu'un seul enregistrement dans une table soit considéré comme la valeur "par défaut" pour d'autres requêtes ou vues qui pourraient accéder à cette table.
Fondamentalement, je veux garantir que cette requête renvoie toujours exactement une ligne:
SELECT ID, Zip
FROM PostalCodes
WHERE isDefault=True
Comment pourrais-je faire cela en SQL?
mysql
database-design
emaynard
la source
la source
PostalCodes
est vide? Si une ligne a déjà une propriété, la propriété doit être empêchée d'être définie sur false à moins qu'une autre ligne (s'il en existe une) soit définie sur true dans la même instruction SQL. Les lignes nulles peuvent-elles avoir la propriété entre les limites de transaction? La dernière ligne du tableau doit-elle être obligée d'avoir la propriété et ne pas être supprimée? L'expérience me dit que «garantir exactement une rangée» a tendance à signifier quelque chose de différent en réalité, souvent simplement «au plus une rangée».Réponses:
Edit: ceci est adapté à SQL Server avant de connaître MySQL
Il y a
45 façons de procéder: par ordre du plus désiré au moins désiréNous ne savons pas à quoi sert le SGBDR si bien que tous ne s'appliquent pas
La meilleure façon est un index filtré. Cela utilise DRI pour maintenir l'unicité.
Colonne calculée avec unicité (voir la réponse de Jack Douglas) (ajoutée par la modification 2)
Une vue indexée / matérialisée qui ressemble à un index filtré utilisant DRI
Déclencheur (selon les autres réponses)
Vérifiez la contrainte avec un UDF. Ce n'est pas sûr pour l'isolement simultané et instantané. Voir un deux trois quatre
Notez que l'exigence pour "un défaut" est sur la table, pas la procédure stockée. La procédure stockée aura les mêmes problèmes de concurrence qu'une contrainte de vérification avec un udf
Remarque: demandé plusieurs fois:
la source
Remarque: Cette réponse a été donnée avant qu'il ne soit clair que le demandeur voulait quelque chose de spécifique à MySQL. Cette réponse est biaisée vers SQL Server.
Appliquez une contrainte CHECK à la table qui appelle un UDF et assurez-vous que sa valeur de retour est <= 1. L'UDF peut simplement compter les lignes de la table WHERE
isDefault = TRUE
. Cela garantira qu'il n'y a pas plus d'une ligne par défaut dans le tableau.Vous devez ajouter un bitmap ou un index filtré sur la
isDefault
colonne (en fonction de votre plate-forme) pour vous assurer que cette UDF s'exécute très rapidement.Avertissements
PostalCodes
table, mais cela reste un problème de performances pour les situations où une activité basée sur un ensemble est probable.Compte tenu de toutes ces mises en garde, je recommande d'utiliser la suggestion de gbn d'un index unique filtré au lieu d'une contrainte de vérification.
la source
Voici une procédure stockée (MySQL Dialect):
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:
Au lieu d'une procédure stockée, que diriez-vous d'un déclencheur?
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:
la source
Vous pouvez utiliser un déclencheur pour appliquer les règles. Lorsqu'une instruction UPDATE ou INSERT définit isDefault sur True, le SQL dans le déclencheur peut définir toutes les autres lignes sur False.
Vous devrez prendre en compte d'autres situations lors de l'application de cette option. Par exemple, que doit-il se passer si plusieurs lignes et UPDATE ou INSERT définissent isDefault sur True? Quelles règles s'appliqueront pour éviter d'enfreindre la règle?
Aussi, est-ce possible la condition où il n'y a pas de défaut? Que se passe-t-il lorsqu'une mise à jour définit l'isDefault de True à False.
Une fois que vous avez défini les règles, vous pouvez les créer dans le déclencheur.
Ensuite, comme indiqué dans une autre réponse, vous souhaitez appliquer une contrainte de vérification pour aider à appliquer les règles.
la source
Ce qui suit configure un exemple de table et de données:
Si vous créez une procédure stockée pour définir l'indicateur IsDefault et supprimer les autorisations pour modifier la table de base, vous pouvez appliquer cela avec la requête ci-dessous. Cela nécessiterait une analyse de table à chaque fois.
Selon la taille de la table, un index sur IsDefault (DESC) peut entraîner une ou les deux requêtes ci-dessous en évitant une analyse complète.
Si vous ne pouvez pas supprimer les autorisations de la table de base, devez appliquer l'intégrité par d'autres moyens et utilisez SQL2008, vous pouvez utiliser un index unique filtré:
la source
Pour MySQL qui n'a pas d'index filtrés, vous pouvez faire quelque chose comme ceci. Il exploite le fait que MySQL autorise plusieurs NULL dans des index uniques, et utilise une table dédiée et une clé étrangère pour simuler un type de données qui ne peut avoir que NULL et 1 comme valeurs.
Avec cette solution, au lieu de true / false, vous utiliseriez simplement 1 / NULL.
La seule chose qui peut mal tourner, je pense, c'est que quelqu'un ajoute une ligne au
DefaultFlag
tableau. Je pense que ce n'est pas un gros problème, et vous pouvez toujours le réparer avec des autorisations si vous voulez vraiment être en sécurité.la source
Cela vous posait essentiellement des problèmes parce que vous aviez placé le champ au mauvais endroit et c'est tout.
Ayez une table 'Defaults', avec PostalCode dedans, qui contient l'identifiant que vous recherchez. En général, il est également bon de nommer vos tables en fonction d'un enregistrement, donc le nom de votre table initiale serait mieux appelé «PostalCode». Les valeurs par défaut seront une table à une seule ligne, jusqu'à ce que vous ayez besoin de spécialiser vos valeurs par défaut avec une autre configuration (comme les historiques).
La dernière requête que vous souhaitez est la suivante:
la source