2009-08-29 8 views
2

J'ai une colonne de texte qui devrait avoir seulement 1 des 3 chaînes possibles. Pour mettre une contrainte dessus, je devrais référencer une autre table. Puis-je à la place mettre les valeurs de la contrainte directement sur la colonne sans faire référence à une autre table?Puis-je mettre une contrainte sur une colonne sans faire référence à une autre table?

+0

Publiez quelle plateforme de base de données vous utilisez. Regardez toutes ces personnes pauvres qui répondent à vos questions avec plusieurs plates-formes, en sortant de leur manière de vous s'il vous plaît. –

+0

regardez l'étiquette qui dit sql – zsharp

+0

et était aussi en titre mais Bill l'a édité – zsharp

Répondre

5

Si c'est SQL Server, Oracle, ou PostgreSQL, oui, vous pouvez utiliser un check constraint.

Si c'est MySQL, check constraint sont reconnus mais non appliqués. Vous pouvez utiliser un enum, cependant. Si vous avez besoin d'une liste séparée par des virgules, vous pouvez utiliser un set. Cependant, ceci est généralement mal vu, car il n'est définitivement pas facile à maintenir. Il est préférable de créer une table de recherche et d'assurer l'intégrité référentielle à travers cela.

+0

"Cependant, ceci est généralement mal vu, car il n'est certainement pas optimisé." - Avez-vous une chance de fournir un lien vers une explication? Je suppose que vous voulez dire que les contraintes affectent la performance des mises à jour/insertions - et une table de recherche est certainement une meilleure solution pour la question originale - mais j'aimerais en voir plus sur l'impact sur les performances. – Mayo

+0

'@ mmayo': une contrainte' CHECK' est plus difficile à maintenir qu'une table de recherche 'FOIREGN KEY', mais' CHECK' est plus efficace qu'une table de recherche dans tous les systèmes mais 'MySQL' (qui ne supporte pas' CHECK' contraintes). Dans 'MySQL', une table de recherche peut être plus efficace qu'une condition' IN' avec une analyse de plage sur une longue liste de prédicats. Voir cet article dans mon blog pour le détail des performances: http://explainextended.com/2009/08/18/passing-parameters-in-mysql-in-list-vs-temporary-table/ – Quassnoi

+0

'@ Eric': pour votre exemple (avec seulement trois valeurs possibles) une table de consultation sera moins efficace même dans 'MySQL'. Il ne paie que pour les très longues listes qui doivent être conservées dans une table de recherche pour des raisons de maintenabilité et non de performance. – Quassnoi

2

Dans Oracle, SQL Server et PostgreSQL, utilisez la contrainte CHECK.

CREATE TABLE mytable (myfield INT VARCHAR(50) CHECK (myfield IN ('first', 'second', 'third')) 

En MySQL, utilisez ENUM type de données:

CREATE TABLE mytable (myfield ENUM ('first', 'second', 'third')) 
3

En plus de la contrainte de vérification et le type de données ENUM autre mention, vous pouvez également écrire un déclencheur pour faire respecter votre restriction souhaitée.

Je ne recommande pas forcément un déclencheur en tant que bonne solution, je signale simplement une autre option qui répond à vos critères de ne pas référencer une table de recherche.

Mon habitude est de définir des tables de recherche au lieu d'utiliser des contraintes ou des déclencheurs, quand la règle consiste simplement à restreindre une colonne à un ensemble fini de valeurs. L'impact sur les performances de la vérification par rapport à une table de recherche n'est pas pire que l'utilisation de contraintes ou de déclencheurs CHECK, et il est beaucoup plus facile à gérer lorsque l'ensemble de valeurs peut changer de temps en temps.

Une autre tâche courante consiste à interroger l'ensemble de valeurs autorisées, par exemple pour renseigner un champ de formulaire dans l'interface utilisateur. Lorsque les valeurs autorisées sont dans une table de recherche, cela est beaucoup plus facile que lorsqu'elles sont définies dans une liste de valeurs littérales dans une contrainte CHECK ou dans une définition ENUM.


Re commentaire « comment faire exactement recherche sans id »

CREATE TABLE LookupStrings (
    string VARCHAR(20) PRIMARY KEY 
); 

CREATE TABLE MainTable (
    main_id INT PRIMARY KEY, 
    string VARCHAR(20) NOT NULL, 
    FOREIGN KEY (string) REFERENCES LookupStrings (string) 
); 

Maintenant, vous pouvez être assuré qu'aucune valeur en MainTable.string est invalide, car l'intégrité référentielle empêche que. Mais vous n'avez pas à se joindre à la table LookupStrings pour obtenir la chaîne, lorsque vous interrogez MainTable:

SELECT main_id, string FROM MainTable; 

Voir? Pas de jointure! Mais vous obtenez la valeur de chaîne.


Re commentaires sur plusieurs colonnes de clé étrangère:

Vous pouvez avoir deux clés étrangères individuels, chacun pointant potentiellement à différentes lignes de la table de consultation.La colonne de clé étrangère n'a pas besoin d'être nommée la même que la colonne dans la table référencée.

Mon exemple courant est une base de données de suivi de bogues, dans laquelle un bogue a été signalé par un utilisateur, mais assigné à un utilisateur différent. Les deux reported_by et assigned_to sont des clés étrangères faisant référence à la table Accounts.

CREATE TABLE Bugs (
    bug_id INT PRIMARY KEY, 
    reported_by INT NOT NULL, 
    assigned_to INT, 
    FOREIGN KEY (reported_by) REFERENCES Accounts (account_id), 
    FOREIGN KEY (assigned_to) REFERENCES Accounts (account_id) 
); 
+0

une note, avec 2 clés étrangères, le serveur sql n'autorise pas les changements en cascade dans les deux colonnes. correct? – zsharp

+0

Non, je ne crois pas qu'une telle limitation existe. –

Questions connexes