Verbinden Sie die Tabelle mit einem anderen mit mehreren Fremdschlüsseln in die gleiche Tabelle

Ich habe eine Tabelle mit Kategorie-Codes, die in einer anderen Tabelle aufgelistet sind, gibt es 8 Kategorie-Codes und derzeit mache ich die unten (unten ist massiv vereinfacht):

SELECT HeaderCode , C1.CategoryName AS C1 , C2.CategoryName AS C2 , C3.CategoryName AS C3 , C4.CategoryName AS C4 , C5.CategoryName AS C5 , C6.CategoryName AS C6 , C7.CategoryName AS C7 , C8.CategoryName AS C8 FROM Header H INNER JOIN Cats C1 ON H.Cat1 = C1.CategoryID INNER JOIN Cats C2 ON H.Cat2 = C2.CategoryID INNER JOIN Cats C3 ON H.Cat3 = C3.CategoryID INNER JOIN Cats C4 ON H.Cat4 = C4.CategoryID INNER JOIN Cats C5 ON H.Cat5 = C5.CategoryID INNER JOIN Cats C6 ON H.Cat6 = C6.CategoryID INNER JOIN Cats C7 ON H.Cat7 = C7.CategoryID INNER JOIN Cats C8 ON H.Cat8 = C8.CategoryID 

SQL Fiddle Beispiel

Ich habe über eine function nachgedacht, um die data zu bekommen, aber es wäre langsam, da es 200.000 datasätze gibt, die ich für diese Informationen benötigen werde.

performance ist so weit in Ordnung, aber es gibt timeen, die ich habe, um dynamische SQL zu verwenden und dies zu tun mit einem anderen 5+ Joins ist ein großes Durcheinander.

Gibt es eine bessere / bequemer / einfacher zu pflegen, dies zu tun?

Angenommen, Sie können Ihr Schema nicht beheben (dh normalisieren Sie Ihr Schema), können Sie eine Inline (!) Tabelle Valued Function wie folgt erstellen:

 CREATE FUNCTION dbo.EightCats(@C1 INT, @C2 INT, @C3 INT, ...) RETURNS TABLE AS RETURN SELECT * FROM (SELECT CategoryName AS C1 FROM dbo.Cats WHERE CategoryId = @C1) T1 CROSS JOIN (SELECT CategoryName AS C2 FROM dbo.Cats WHERE CategoryId = @C2) T2 CROSS JOIN (SELECT CategoryName AS C3 FROM dbo.Cats WHERE CategoryId = @C2) T3 ... 

Dann könntest du deine Frage so schreiben:

 SELECT H.HeaderCode, EC.* FROM dbo.Header H CROSS APPLY dbo.EightCats(H.Cat1,H.Cat2,H.Cat3,H.Cat4,H.Cat5,H.Cat6,H.Cat7,H.Cat8) EC; 

Dies sollte in der gleichen Ausführung Plan, so sollte es keine Performance-Strafe für diese. Wichtig ist, dass Sie diese nur für acht Kategorien verwenden. Wenn du eine andere Abfrage hast, die nur sieben Kategorien hat, musst du eine neue function erstellen. Andernfalls werden Sie (oder eher SQL server) am Ende unnötige Joins machen.

Ich würde das mit einem Brückentisch machen.

 CREATE TABLE HeaderCategory ( HeaderCategoryId int IDENTITY(1,1) NOT NULL , HeaderId int , CategoryId int , SortBy int ) 

Und machen HeaderId und CategoryId Fremdschlüssel zu ihren jeweiligen Tabellen. Die Spalte SortBy wird verwendet, um anzugeben, ob es Kategorie 1, 2, 3 usw. ist.

Dies ist die "normalisierte" Architektur.

Dann, um die gleiche Abfrage Ausgabe, die Sie in Ihre Frage bekommen, eine einfache PIVOT-Abfrage zu bekommen.

Wenn du deine Tabellen nicht ändern willst, gibt es zwei weitere Möglichkeiten: 1) Schreibe eine function "GetCategoryName" (CategoryId) und verwende sie in deiner Auswahl wie folgt: SELECT Header, GetCategoryName (Kategorie1) AS C1, …

2) Erstellen Sie eine VIEW, die die CategoryNames enthält.