2009-04-17 9 views

Antwort

49

Mit einem Fremdschlüssel zu einer Lookup-Tabelle ist der Ansatz, den ich verwende. Tatsächlich benutze ich das sogar, wenn ich eine Datenbank verwende, die ENUM unterstützt (z. B. MySQL).

Der Einfachheit halber überspringe ich das immer vorhandene "id" für die Nachschlagetabelle und verwende einfach den tatsächlichen Wert, den ich in meiner Haupttabelle benötige, als Primärschlüssel der Nachschlagetabelle. Auf diese Weise müssen Sie keinen Join durchführen, um den Wert zu erhalten.

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) 
); 

Zwar nimmt Strings speichert mehr Platz als MySQL-Implementierung von ENUM, aber es sei denn, die betreffende Tabelle Millionen von Zeilen hat, es spielt kaum eine Rolle.

Weitere Vorteile der Lookup-Tabelle sind, dass Sie einen Wert aus der Liste mit einer einfachen INSERT oder DELETE hinzufügen oder entfernen können, während bei ENUM Sie haben ALTER TABLE zu verwenden, um die Liste neu zu definieren.

Versuchen Sie auch, die aktuelle Liste zulässiger Werte in einer ENUM abzufragen, z. B. um eine Auswahlliste in Ihrer Benutzerschnittstelle zu füllen. Es ist ein großer Ärger! Mit einer Nachschlagetabelle ist es einfach: SELECT status from BugStatus.

Sie können auch weitere Attributspalten zur Nachschlagetabelle hinzufügen, wenn dies erforderlich ist (z. B. zum Markieren von Auswahlmöglichkeiten, die nur für Administratoren verfügbar sind). In einem ENUM können Sie die Einträge nicht kommentieren; Sie sind nur einfache Werte.

Eine weitere Option neben einer Lookup-Tabelle CHECK Einschränkungen (vorausgesetzt, die Datenbank unterstützt sie - MySQL nicht der Fall ist) zu verwenden wäre:

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

Aber diese Verwendung einer CHECK Zwang leidet unter dem gleichen Nachteile wie die ENUM: schwer zu ändern, die Liste der Werte ohne ALTER TABLE, schwer die Liste der zulässigen Werte abzufragen, schwer zu kommentieren Werte.

PS: der Gleichheitsvergleichsoperator in SQL ist eine einzige =. Die doppelte == hat keine Bedeutung in SQL.

+0

Danke für die = vs. == sache :) Es ist eine Weile her, seit ich SQL direkt benutzt habe. – epochwolf

+0

große Antwort, +1 von mir. – Brann

+0

Eine bisschen alte Frage, aber tolle Antwort. Stimme hoch. –

-1

Ich würde ein Varchar verwenden. Ist das nicht eine Option für dich?

+0

Die Verwendung eines VARCHAR würde zu denormalisierten Daten führen. Wenn Sie den Namen des Aufzählungswerts ändern möchten, ist eine Aktualisierung der gesamten Tabelle erforderlich, anstatt nur eine einzelne Zeile in einer Referenztabelle zu ändern. –

1

Sie haben grundsätzlich zwei Möglichkeiten:

  • Verwendung ein Integer-Feld

  • VARCHAR Feld Ich persönlich

verwenden würde die Verwendung von Varchars befürworten, weil Sie ‚gewonnen t brechen Sie nichts, wenn Sie Ihre Enum ändern + die Felder sind menschenlesbar, aber ints haben auch einige Pro, nämlich Leistung (die Größe der Daten ist ein offensichtliches Beispiel)

2

Um die möglichen Werte einzuschränken, würde ich einen Fremdschlüssel zu einer Tabelle verwenden, die die Aufzählungselemente enthält.

Wenn Sie nicht möchten, dass JOIN Ihre Suchen durchführt, dann machen Sie den Schlüssel zu einem VARCHAR, wenn JOINS kein Problem ist, dann machen Sie den Schlüssel zu einem INT und treten nur ein, wenn Sie in diesem Feld suchen müssen.

Beachten Sie, dass das Einfügen Ihrer Enumerationen in die DB die Überprüfung der Werte in Ihrem Code durch die Kompilierzeit ausschließt (sofern Sie die Enumeration im Code nicht duplizieren). Ich habe festgestellt, dass dies eine große negative Seite ist.

0

Dies ist, was ich

In meinem Hibernate kürzlich

tat kartiert POJO- Ich hielt den Typ des Elements als String und es ist VARCHAR in der Datenbank.

Der Setter für das dauert eine ENUM Es gibt einen anderen Setter, die String- nimmt aber das ist privat (oder das Feld directly- abbilden kann, wenn das ist, was Sie bevorzugen.)

Nun ist die Tatsache, ich bin mit String ist von allen gekapselt. Für den Rest der Anwendung verwenden meine Domain-Objekte enum. Und soweit es die Datenbank betrifft - ich benutze String.

Wenn ich deine Frage verpasst habe - ich entschuldige mich.

+0

Das macht Sinn. Ruby on Rails erlaubt das gleiche Verhalten mit Validierungen als Bonus. – epochwolf

Verwandte Themen