2009-04-17 8 views
18

Comment implémenter un champ d'énumération dans une base de données qui ne supporte pas les énumérations? (c'est-à-dire SQLite)Comment gérer les énumérations sans champs enum dans une base de données?

Les champs doivent être facilement consultables avec "field =?" Donc, en utilisant n'importe quel type de sérialisation des données est une mauvaise idée.

+0

S'il s'agit d'un doublon, s'il vous plaît soyez gentil. J'ai cherché la réponse sur StackOverflow avant de le demander. – epochwolf

Répondre

49

L'utilisation d'une clé étrangère dans une table de recherche est l'approche que j'utilise. En fait, je l'utilise même lorsque j'utilise une base de données qui supporte ENUM (par exemple MySQL). Pour simplifier, je peux omettre l'omniprésent «id» pour la table de recherche, et utiliser simplement la valeur réelle dont j'ai besoin dans ma table principale comme clé primaire de la table de recherche. De cette façon, vous n'avez pas besoin de faire une jointure pour obtenir la valeur.

CREATE TABLE BugStatus (
    status   VARCHAR(20) PRIMARY KEY 
); 

INSERT INTO BugStatus (status) VALUES ('NEW'), ('OPEN'), ('FIXED'); 

CREATE TABLE Bugs (
    bug_id   SERIAL PRIMARY KEY, 
    summary   VARCHAR(80), 
    ... 
    status   VARCHAR(20) NOT NULL DEFAULT 'NEW', 
    FOREIGN KEY (status) REFERENCES BugStatus(status) 
); 

Certes, le stockage des chaînes prend plus de place que la mise en œuvre de MySQL de ENUM, mais à moins que la table en question a des millions de lignes, il importe peu.

D'autres avantages de la table de consultation sont que vous pouvez ajouter ou supprimer une valeur dans la liste avec un simple INSERT ou DELETE, alors qu'avec ENUM vous devez utiliser ALTER TABLE pour redéfinir la liste.

Essayez également d'interroger la liste actuelle des valeurs autorisées dans un ENUM, par exemple pour remplir une liste de sélection dans votre interface utilisateur. C'est un gros ennui! Avec une table de recherche, c'est facile: SELECT status from BugStatus.

Vous pouvez également ajouter d'autres colonnes d'attributs à la table de recherche si vous en avez besoin (par exemple pour marquer les choix disponibles uniquement pour les administrateurs). Dans un ENUM, vous ne pouvez pas annoter les entrées; ce ne sont que des valeurs simples.

Une autre option en plus d'une table de consultation serait d'utiliser CHECK contraintes (à condition que la base de données les prend en charge - MySQL ne fonctionne pas):

CREATE TABLE Bugs (
    bug_id   SERIAL PRIMARY KEY, 
    summary   VARCHAR(80), 
    ... 
    status   VARCHAR(20) NOT NULL 
    CHECK (status IN ('NEW', 'OPEN', 'FIXED')) 
); 

Mais cette utilisation d'une contrainte CHECK souffre de la même inconvénients que le ENUM: difficile de changer la liste des valeurs sans ALTER TABLE, difficile d'interroger la liste des valeurs autorisées, difficiles à annoter les valeurs. PS: l'opérateur de comparaison d'égalité dans SQL est =. Le double == n'a aucune signification en SQL.

+0

Merci pour la chose = = == :) Ça fait longtemps que j'ai utilisé SQL directement. – epochwolf

+0

bonne réponse, +1 de moi. – Brann

+0

Un peu vieille question, mais une réponse géniale. Votez. –

-1

Je voudrais utiliser un varchar. Est-ce que ce n'est pas une option pour vous?

+0

L'utilisation d'un VARCHAR conduirait à des données dénormalisées. Si vous voulez changer le nom de la valeur enum, cela nécessite une mise à jour sur toute la table, plutôt que de simplement changer une seule ligne dans une table de référence. –

1

Vous avez essentiellement deux options:

  • utiliser un champ entier

  • utiliser un champ varchar

Je préconiserais personnellement l'utilisation de varchars, parce que vous avez gagné » t casse quoi que ce soit si vous changez votre énumération + les champs sont lisibles par l'homme, mais ints ont quelques pro aussi, à savoir la performance (la taille des données est un exemple évident)

2

Pour restreindre les valeurs possibles, j'utiliserais une clé étrangère dans une table contenant les éléments d'énumération. Si vous ne voulez pas JOIN pour faire vos recherches, alors faites une clé varchar si JOINS n'est pas un problème, puis faites une INT et ne joignez pas la clé sauf si vous avez besoin de chercher dans ce champ. Notez que mettre vos énumérations dans la base de données interdit de compiler le temps de vérification des valeurs dans votre code (sauf si vous dupliquez l'énumération dans le code). J'ai trouvé que c'était un gros inconvénient.

0

C'est ce que je l'ai fait récemment

Dans mon mise en veille prolongée cartographié POJO- j'ai gardé le type de membre en tant que chaîne et il est VARCHAR dans la base de données.

Le compositeur pour cela prend un ENUM Il y a un autre compositeur qui prend String- mais est privée (ou vous pouvez mapper le directly- sur le terrain si c'est ce que vous préférez.)

Maintenant, le fait que je me sers La chaîne est encapsulée de tous. Pour le reste de l'application, les objets de mon domaine utilisent enum. Et en ce qui concerne la base de données, j'utilise String.

Si j'ai raté votre question, je m'en excuse.

+0

Cela a du sens. Ruby on Rails permettrait le même comportement avec des validations en bonus. – epochwolf

Questions connexes