2010-12-02 16 views
0

Ich habe eine Tabelle mit Leuten, die ziemlich normal sind, z. :Speichern von Suchsätzen basierend auf mehreren Bedingungen

CREATE TABLE [Contact](
[ContactID] [bigint] IDENTITY(1,1) NOT NULL, 
[ContactType] [nvarchar](50) NULL, 
[Forename] [nvarchar](60) NULL, 
[Surname] [nvarchar](60) NULL, 
[Company] [nvarchar](60) NULL 
} 

Example Data : 
01, "Student", "Bob", "Smith", Blank 
02, "Staff", "Robert", "Smithe", "Roberts And Sons" 
Etc 

Diese Tabelle enthält alle Felder, die allen Kontakten gemeinsam sind. Jedoch habe ich einige "Typen" von Kontakten, die ein Feld haben können oder nicht, das nur für diese Art von Kontakt spezifisch ist. Wenn der Datensatz beispielsweise "ContactType = 'student'" hat, möchte ich ein zusätzliches Feld namens "studentid" speichern. Es gibt viele verschiedene Arten von Kontakten mit jeweils leicht unterschiedlichen Feldanforderungen. Um dieser Situation zu irgendeinem Zeitpunkt in der Zukunft hinzuzufügen, können für jeden Kontakttyp zusätzliche Felder hinzugefügt werden.

Wenn ich jedes Feld zur Tabelle Kontakte hinzufüge, würde ich am Ende mit vielen Feldern, die nicht für 99% der Datensätze benötigt werden. So plane ich auf eine zweite Tabelle wie folgt zu erstellen:

CREATE TABLE [ContactMetaData](
[ContactID] [bigint] NOT NULL, 
[PropName] [nvarchar](200) NOT NULL, 
[PropData] [nvarchar](200) NULL 
) 

Example Data: 
01, "StudentID", "" 
01, "CourseName", "IT" 
01, "Average", "10" 
02, "Ranking", "22" 
02, "ProductTypes", "IT Equipment" 
ETC 

Für jedes zusätzliche Feld i fügen Sie einfach einen Datensatz in dieser Tabelle mit dem Namen und den Wert für das Feld. Ich kann Code verwenden diese Informationen zu ziehen usw.

Meine Frage ist

Ist dies der beste Ansatz, wie ich einer anderen Art und Weise ratlos bin anders als eine große Tabelle mit jedem einzelnen Feld. Mit diesem Ansatz ist es möglich, komplexe Abfragen in vielen der Immobilienfelder durchzuführen und wenn ja wie? z.B. wie würde ich alle studenten auf dem "IT" kurs mit einem "Durchschnitt" von 10 aufzählen whos "vorname" beginnt mit "D"?

Antwort

0

Ja, wenn Sie wirklich viele Felder haben, die nicht verwendet werden, gehen Sie für diesen Ansatz (genannt EAV data structure). Sie können alle Abfragen für diese Struktur ausführen, die Sie mit einem normalen Modell ausführen können. Verwenden Sie einfach geeignete Joins, um sie zu drehen.

+0

Da Sie nicht MySQL verwenden, haben Sie eine gute Chance, dass diese Joins auch eine gute Leistung haben. – AndreKR

+0

Danke für die Antwort, die abläuft, um EAV-Strukturen nachzuschlagen. – Jammy

0

Ihr vorgeschlagener objektbasierter Ansatz ist sinnvoll, insbesondere wenn neue Kontakttypen und Eigenschaften zur Laufzeit erstellt werden müssen, ohne das Schema zu ändern.

Wenn die Menge der Kontakttypen und -eigenschaften zur Laufzeit festgelegt ist, können Sie alternativ eine Untertabelle für jeden Typ erstellen. Das heißt, Tabellen wie StudentInfo, StaffInfo usw. erstellen. Wenn Sie dies getan hätten, würden Sie das Feld ContactType nicht mehr benötigen, da es bei Vorhandensein einer Zeile in der entsprechenden Untertabelle implizit wäre. Dieses Modell würde auch schwierige Situationen handhaben, in denen jemand in zwei Kategorien fällt, z.B. ein Student, der auch Mitarbeiter ist.

Ignorieren Sie all dies jedoch, schauen wir uns Ihre zweite Frage zum Abfragen der Eigenschaftstabellen an. Sie können solche Abfragen durchführen. Ihr Beispiel würde von dieser Abfrage zu beantworten:

SELECT * 
FROM Contact AS c 
INNER JOIN ContactMetaData AS crs 
    ON crs.ContactId = c.ContactId 
    AND crs.PropName = 'CourseName' 
    AND crs.PropData = 'IT' 
INNER JOIN ContactMetaData AS av 
    ON av.ContactId = c.ContactId 
    AND av.PropName = 'Average' 
    AND av.PropData = 10 
WHERE c.Forename LIKE 'D%' 

Der Trick ist, die ContactMetaData Tabelle mehrere Male, einmal für jede benutzerdefinierte Eigenschaft Sie testen möchten beizutreten.

Ein Problem mit dieser Art von Abfrage ist, dass es fast sicher zur Laufzeit generiert werden muss - schließlich ist die Menge der Eigenschaften zur Laufzeit dynamisch.Sie können dies vermeiden, indem Sie einen anderen Ansatz, die Abfrage zum Ausdruck:

DECLARE @propertyCriteria TABLE (
    PropName NVARCHAR(200) NOT NULL, 
    PropData NVARCHAR(200) NULL 
) 

INSERT INTO @propertyCriteria VALUES ('CourseName', 'IT') 
INSERT INTO @propertyCriteria VALUES ('Average', '10') 

SELECT * 
FROM Contact AS c 
WHERE c.Forename LIKE 'D%' 
AND NOT EXISTS (
    SELECT * 
    FROM @propertyCriteria AS crit 
    LEFT JOIN ContactMetaData AS meta 
    ON meta.ContactId = c.ContactId 
    AND meta.PropName = crit.PropName 
    AND meta.PropData = crit.PropData 
    WHERE meta.ContactId IS NULL 
) 

Dies hat den Vorteil, dass die Abfrage nun zur Laufzeit festgelegt ist als die dynamische Eigenschaft Kriterien bestimmt werden, was in die temporäre Tabelle eingefügt wird @propertyCriteria. Die Nachteile sind, dass jetzt die temporäre Tabelle benötigt wird und dass die Abfrage nicht so gut funktioniert wie bei inneren Joins (obwohl Sie wahrscheinlich den Unterschied nicht bemerken werden, wenn Ihre Datenbank nur 50.000 Datensätze enthält). Beachten Sie auch, dass dieser zweite Ansatz nur für Kriterien funktioniert, die UND-verknüpft sind. Wenn Sie ORs wollen, wird die Lösung noch komplexer.

Übrigens, wenn Sie NULLs sowohl in den Eigenschaftswerten als auch in den Kriterien zulassen, sollten Sie nicht vergessen, dass Vergleichsoperatoren, die NULLs enthalten, immer false zurückgeben (dh NULL = NULL ist falsch, NULL <>) NULL ist falsch, usw.).

Verwandte Themen