2013-04-24 99 views
0

我有一个表中的类别代码列在另一个表中,有8个类别代码,目前我在做以下(下面是大量简化):加入到另一个具有多个外键的表到另一个表

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 Example

我没想到一个函数来获取数据,但因为有200,000条记录,我需要得到这个信息,这将是缓慢的。

性能是迄今为止不错,但有次我不得不使用动态SQL,并与另一这样5+加入是一个很大的混乱。

是否有更好/更方便/更容易维护的方式来做到这一点? (!)

回答

1

假如你不能修复你的架构(意思是,你的标准化模式),您可以创建一个内嵌表值函数是这样的:

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 
    ... 

然后,你可以写你的查询是这样的:

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; 

这应该导致相同的执行计划,所以不应该有性能损失。重要的是,你只用于八个类别。如果您有另一个只有七个类别的查询,则需要创建一个新的函数。否则,你(或者说SQL Server)最终会做不必要的连接。

0

我会做一个桥表。

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

并使HeaderId和CategoryId外键到它们各自的表。所述SortBy柱用于指示它是否是类别1,2,3,等等

这是更“归一化”的体系结构。

然后让你在你的问题得到同样的查询输出,做一个简单的PIVOT查询。

如果你不想改变你的表,其他两个可能性: 1)写GetCategoryName(类别ID)功能,并在您选择这样使用它: SELECT头,GetCategoryName(组别)为C1, ...

2)创建一个包含CategoryNames的VIEW。

相关问题