2008-09-17 5 views
4

ich zur Zeit versucht, das Design einer Legacy-DB zu verbessern, und ich habe die folgende SituationDatenbank-Design-Lookup-Tabellen

Zur Zeit habe ich eine Tabelle SalesLead in dem wir die die LeadSource speichern.

Create Table SalesLead(
    .... 
    LeadSource varchar(20) 
    .... 
) 

Die Lead Sources werden hilfreich in einer Tabelle gespeichert.

Create Table LeadSource (
    LeadSourceId int, /*the PK*/ 
    LeadSource varchar(20) 
) 

Und so möchte ich nur von einem Fremdschlüssel erstellen, um den anderen und die nicht-normalisierte Spalte fallen.

Alle üblichen Sachen, hoffe ich.

Hier ist mein Problem. Ich kann nicht von dem Problem zu erhalten scheinen weg, dass anstelle des Schreibens

SELECT * FROM SalesLead Where LeadSource = 'foo' 

, die völlig eindeutig ist ich jetzt

SELECT * FROM SalesLead where FK_LeadSourceID = 1 

oder

SELECT * FROM SalesLead 
INNER JOIN LeadSource ON SalesLead.FK_LeadSourceID = LeadSource.LeadSourceId 
where LeadSource.LeadSource = "foo" 

Was, wenn wir bricht schreiben Ändern Sie den Inhalt des LeadSource-Felds.

In meiner Anwendung, wann immer ich den Wert SalesLead des LeadSource verändern wollen Ich möchte von 1 bis 2 nicht aktualisieren (zum Beispiel), wie ich will nicht Entwickler haben mit diesen magischen Zahlen erinnern . Die IDs sind willkürlich und sollten so gehalten werden.

Wie entferne oder negiere ich die Abhängigkeit von ihnen im Code meiner App?

bearbeiten Sprachen meine Lösung unterstützen müssen

  • .NET 2.0 + 3 (für das, was ihren Wert asp.net, vb.net und C#)
  • vba (Zugang)
  • db (MSSQL 2000)

Edit 2.0 Die feine Join ist nur tha t 'foo' kann sich auf Anfrage zu 'foobar' ändern und ich möchte die Abfragen nicht durchziehen.

Antwort

1

Haben Sie eine aktualisierbare Ansicht in Betracht gezogen? Abhängig von Ihrem Datenbankserver und der Integrität Ihres Datenbankentwurfs können Sie eine Ansicht erstellen, die bei einer Änderung der Werte wiederum die einzelnen Tabellen aktualisiert.

3

Wenn Sie die Tabelle de-normalisieren möchten, fügen Sie die LeadSource (Varchar) -Spalte einfach zu Ihrer SalesLead-Tabelle hinzu, anstatt eine FK oder eine ID zu verwenden.

Auf der anderen Seite, wenn Sie Ihre Sprachunterstützung für ENUM Strukturen hat, die „magischen Zahlen“ sicher in einer Enum gespeichert werden sollen, so können Sie:

SELECT * FROM SALESLEAD WHERE LeadSouce = (int) EnmLeadSource.Foo; //pseudocode 

Und Ihr Code eine

haben

Es ist in Ordnung, einige übermäßige Normalisierung zu entfernen, wenn dies mehr Probleme verursacht, als was es behebt. Beachten Sie jedoch, dass Sie bei der Verwendung eines VARCHAR-Felds (im Gegensatz zu einer Magic Number) Konsistenz beibehalten müssen und es später schwierig sein könnte, sie zu lokalisieren, wenn Sie mehrere Sprachen oder Kulturen benötigen.

Der beste Ansatz nach der Normalisierung scheint die Verwendung einer Enum-Struktur zu sein. Es hält den Code sauber und Sie können enums immer über Methoden und Funktionen übergeben. (Ich nehme .NET hier, aber auch in anderen Sprachen an)

Update: Da Sie .NET verwenden, ist das DB-Backend "irrelevant", wenn Sie eine Abfrage über Code erstellen. Stellen Sie sich diese Funktion vor:

public void GiveMeSalesLeadGiven(EnmLeadSource thisLeadSource) 
{ 
    // Construct your string using the value of thisLeadSource 
} 

In der Tabelle haben Sie eine LeadSource (INT) -Spalte. Aber die Tatsache, dass es 1,2 oder N hat, ist dir egal. Wenn Sie später foo zu foobar ändern müssen, kann das bedeuten:

1) Alle "Nummer 1" muss die Nummer "2" sein. Sie müssen die Tabelle aktualisieren. 2) Oder Sie brauchen Foo, um jetzt Nummer 2 und Bar Nummer 1 zu sein. Sie ändern nur die Enum (aber stellen Sie sicher, dass die Tabellenwerte konsistent bleiben).

Die Enum ist eine sehr nützliche Struktur, wenn sie richtig verwendet wird.

Hoffe, das hilft.

0

Ich sehe dein Problem wirklich nicht hinter dem Beitritt.

Natürlich ist die Frage direkt von der FK_LeadSourceID falsch, aber die Verwendung des JOIN scheint der richtige Weg zu sein, da ich die Änderung der IDs vollkommen in Ordnung maskiere. Wenn beispielsweise "foo" an einem Tag 3 wird (und Sie das Feld für den Fremdschlüssel aktualisieren), funktioniert die letzte angezeigte Abfrage immer noch genauso.

Wenn Sie die Änderung am Schema vornehmen möchten, ohne die aktuellen Abfragen in der Anwendung zu ändern, dann ist eine Ansicht, die diese Verknüpfung umfasst, der richtige Weg.

Oder wenn Sie befürchten, dass die Join-Syntax ist nicht intuitiv, gibt es immer die subselect ...

SELECT * FROM SalesLead where FK_LeadSourceID = 
     (SELECT LeadSourceID from LeadSource WHERE LeadSource = 'foo') 

aber denken Sie daran, einen Index für LeadSource.LeadSource zu halten - zumindest, wenn Sie haben eine Menge von Sie sind in der Tabelle gespeichert.

+0

das Problem ist, dass, wenn wenn foo zu foobar geändert wird dann müssen alle meine Abfragen aktualisiert werden –

0

Wenn Sie "Design verbessern", indem Sie neue Relationen/Tabellen einführen, werden Sie sicherlich verschiedene Entitäten benötigen. Wenn ja, müssen Sie sich mit ihrer Semantik befassen.

In der vorherigen Lösung konnten Sie nur den LeadSource-Namen auf den gewünschten Wert in der entsprechenden SalesLead-Zeile aktualisieren. Wenn Sie den Namen in Ihrer neuen Struktur aktualisieren, tun Sie dies für alle SalesLead-Zeilen.

Es gibt keinen Weg um mit dieser unterschiedlichen Semantik umzugehen. Du musst es nur tun.Um die Tabellen leichter abzufragen, können Sie Ansichten wie bereits vorgeschlagen verwenden, aber ich würde sie meistens für Berichtszwecke oder Abwärtskompatibilität erwarten, vorausgesetzt, sie sind nicht aktualisierbar, da jeder, der diese Ansicht aktualisiert, nicht von einer geänderten Semantik erfährt .

Wenn Sie nicht mögen die SELECT * FROM SalesLead versuchen verbinden, in dem LeadSourceId IN (SELECT ID FROM LeadSource WHERE LeadSource = 'foo')

+0

Dies ist der Gedanke hinter dem verbesserten Design. Wenn ich alle meine Leads von "Joel" bekomme, der seinen Namen in "Jeff" ändert, dann möchte ich, dass alle Leads, die von Joel stammen, auf "Jeff" aktualisiert werden. –

0

In einer typischen Anwendung würde der Benutzer mit einer Liste von Bleiquellen präsentiert werden (zurückgegeben, indem die LeadSource-Tabelle abgefragt wird) und die nachfolgende SalesLead-Abfrage wird von der Anwendung basierend auf der Auswahl des Benutzers dynamisch erstellt.

Ihre Anwendung scheint einige "bekannte" Quellen zu enthalten, für die Sie spezifische Abfragen schreiben müssen. Wenn dies der Fall ist, fügen Sie der LeadSource-Tabelle ein drittes (eindeutiges) Feld hinzu, das einen invarianten Namen enthält, den Sie als Grundlage für die Abfragen Ihrer Anwendung verwenden können.

Dies verschiebt die Last von magic-ness von einer DB erzeugten magischen Zahl (die von Installation zu Installation variieren kann) zu einem systemdefinierten magischen Namen (der durch das Design festgelegt wird).

0

Hier ist eine falsche Dichotomie.

SELECT * FROM SalesLead 
INNER JOIN LeadSource ON SalesLead.FK_LeadSourceID = LeadSource.LeadSourceId 
where LeadSource.LeadSource = "foo" 

brechen nicht mehr als das Original

SELECT * FROM SalesLead Where LeadSource = 'foo' 

wenn foo Änderungen foobar. Wenn Sie parametrisierte Abfragen verwenden (und das sollten Sie wirklich sein), müssen Sie auch nichts ändern, wenn foo in foobar geändert wird.

+0

"bricht nicht mehr als das Original" - vereinbart –

2

Haben Sie darüber nachgedacht, keinen künstlichen Schlüssel für die LeadSource Tabelle zu verwenden? Dann können Sie LeadSource als FK in SalesLead verwenden, was Ihre Abfragen vereinfacht und gleichzeitig die Vorteile einer kanonischen Menge von Werten (die Zeilen in LeadSource) beibehält.

+0

Hank's Antwort ist eine gute Antwort. Ich würde hinzufügen, dass die Verwendung von LeadSource * nicht * denormalizing ist, weil es aussieht, als ob das der echte Code ist. Fügen Sie der Suchtabelle eine beschreibende Spalte hinzu und ändern Sie diese bei Bedarf. –