我有一个表格,其中的类别代码列在另一个表格中,有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
我确实考虑过获取数据的函数但速度很慢,因为我需要200,000条记录来获取这些信息。
性能目前还不错,但有时候我必须使用动态SQL,并且使用另外5个以上的连接执行此操作是一件很麻烦的事。
有更好/更方便/更容易维护的方法吗?
答案 0 :(得分: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)将最终做不必要的连接。
答案 1 :(得分:0)
我会用桥牌表来做这件事。
CREATE TABLE HeaderCategory (
HeaderCategoryId int IDENTITY(1,1) NOT NULL
, HeaderId int
, CategoryId int
, SortBy int
)
将HeaderId和CategoryId外键设为各自的表。 SortBy列用于指示它是否为Category1,2,3等
这是更“规范化”的架构。
然后,为了获得您在问题中获得的相同查询输出,请执行简单的PIVOT查询。
如果您不想更改表格,还有两种可能性: 1)编写一个GetCategoryName(CategoryId)函数,并在你的选择中使用它,如下所示: SELECT Header,GetCategoryName(Category1)AS C1,...
2)创建一个包含CategoryNames的VIEW。