【问题标题】:T-SQL Get Values from Lookup table and use in view / stored procedureT-SQL 从查找表中获取值并在视图/存储过程中使用
【发布时间】:2019-11-09 08:40:03
【问题描述】:

我无法通过搜索找到它,所以我想我问的方式不对,所以欢迎提供帮助。

我们有一个查找表:

Id   Name
------------------
1    "Test"
2    "New"
3    "InProgress"

表2:

StatusId  SomethingElse
  1   
  2

表 1

ID  Other Other StatusId (Fkey to Table2) ...

然后我们有一个从多个表中选择的视图,其中一列是 CASE 语句:

    SELECT * FROM Table1 t1 -- has million records

    CASE When t1.StatusId = 1 THEN (SELECT Name from LOOKUP table where ID = 1) END --'Test'
    CASE When t1.StatusId = 2 THEN (SELECT Name from LOOKUP table where ID = 2) END --'New'
CASE When t3.Date is not null THEN (SELECT Name from LOOKUP table where ID = 3) END --'In Progress'
-- AND ALSO the case look at other tables another 5-6 tables and there are conditions from there
INNER JOIN Table2 t2 on ...
INNER JOIN Table3 t3 on ...

如您所见,这些实际上是静态值。

我想将它们加载到变量中,例如

 @LookUp1 = SELECT [NAME] FROM LookUP WHERE Id = 1, 
 @LookUp2 = SELECT [NAME] FROM LookUP WHERE Id = 2 

并将 CASE 语句中的 select 替换为:

When StatusId = 1 THEN @LookUp
When StatusId = 2 THEN @LookUp2

视图循环遍历数百万条记录,从查找表中为每一行进行选择非常慢。

【问题讨论】:

    标签: sql-server performance tsql


    【解决方案1】:

    为什么不简单地使用连接?

    SELECT <columns list from main table>, Lt.Name
    FROM <main table> As Mt -- Do not use such aliases in real code!
    JOIN <SecondaryTable> As St -- this represents your Table3
        ON <condition> 
    [LEFT] JOIN <Lookup table> As Lt
        ON Mt.StatusId = Lt.Id
        OR (Lt.Id = 3 AND St.Date is not null)
    

    当然,用实际的列列表替换&lt;columns list from main table&gt;,用主表的名称替换&lt;main table&gt;等等。

    连接可能是内连接或左连接,这取决于主表中 StatusId 列的可空性以及是否可以为空,以及在这种情况下您想要获得的内容(名称为空的行或没有行)。

    我已经整理了一个小演示来向您展示我的意思。

    创建和填充示例表(在您以后的问题中保存我们这一步):

    CREATE TABLE LookUp (Id int, Name varchar(10));
    
    INSERT INTO LookUp (Id, Name) VALUES
    (1, 'Test'), (2, 'New'), (3, 'InProgress');
    
    
    CREATE TABLE Table1 (Id int not null, StatusId int null);
    
    INSERT INTO Table1(Id, StatusId)
    SELECT n, CASE WHEN n % 3 = 0 THEN NULL ELSE (n % 3) END
    FROM
    (
        SELECT TOP 30 ROW_NUMBER() OVER(ORDER BY @@SPID) As n
        FROM sys.objects
    ) tally
    
    CREATE TABLE Table3
    (
        Id int not null,
        Date date null
    )
    INSERT INTO Table3 (Id, Date) 
    SELECT Id,  CASE WHEN StatusId IS NULL AND Id % 4 = 0 THEN GetDate() END
    FROM Table1
    

    查询:

    SELECT  Table1.Id, 
            Table1.StatusId, 
            Table3.Date,
            LookUp.Name
    FROM Table1
    JOIN Table3
        ON Table1.Id = Table3.Id
    LEFT JOIN LookUp 
        ON Table1.StatusId = LookUp.Id
        OR (LookUp.Id = 3 AND Table3.Date IS NOT NULL)
    

    结果:

    Id  StatusId    Date            Name
    1   1           NULL            Test
    2   2           NULL            New
    3   NULL        NULL            NULL
    4   1           NULL            Test
    5   2           NULL            New
    6   NULL        NULL            NULL
    7   1           NULL            Test
    8   2           NULL            New
    9   NULL        NULL            NULL
    10  1           NULL            Test
    11  2           NULL            New
    12  NULL        27.06.2019      InProgress
    13  1           NULL            Test
    14  2           NULL            New
    15  NULL        NULL            NULL
    16  1           NULL            Test
    17  2           NULL            New
    18  NULL        NULL            NULL
    19  1           NULL            Test
    20  2           NULL            New
    21  NULL        NULL            NULL
    22  1           NULL            Test
    23  2           NULL            New
    24  NULL        27.06.2019      InProgress
    25  1           NULL            Test
    26  2           NULL            New
    27  NULL        NULL            NULL
    28  1           NULL            Test
    29  2           NULL            New
    30  NULL        NULL            NULL
    

    您也可以在rextester.上观看现场演示

    【讨论】:

    • 因为它在 CASE 语句中,它取决于 w 视图的其他值/行
    • 对于您在问题中显示的场景,我提出的联接是一个更好的选择。如果您的实际情况不同,您无法使用join 而不是case 来实现解决方案,那么问题中的代码示例还不够好,您应该使用代码示例编辑问题这实际上可以准确地证明问题。
    • 可能是例子不好,也可能是我不明白如何应用JOIN。我会稍微编辑一下这个问题。请过一会儿看看
    • 我已编辑 - 可以在我的情况下应用 JOIN 吗?如何应用?
    • 我不明白为什么不这样做。
    【解决方案2】:

    创建一个根据Id返回名称的SQL函数。

    Create FUNCTION [dbo].[GetLookUpValue] 
    (
    @Id int
    )
    RETURNS varchar(500)
    AS BEGIN
        return(Select Name from LOOKUP_table with(nolock) where Id=@Id)
    END
    

    【讨论】:

    • 是的,但这将再次被执行一百万次(对于视图中的每一行)。那是我不想要的。
    • 或左加入您的视图与 LOOKUP 表并获取名称
    • 这是个坏主意。标量函数被称为性能杀手
    • @ZoharPeled 是的,函数是性能杀手,但在这里他不是要速度。
    • OP 可能没有要求速度,但问题确实提到了主表中的数百万行。您建议在这些行的每一行上运行一个已知的性能杀手。你真的认为这不是一个坏主意吗?
    猜你喜欢
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 2021-06-09
    • 2011-05-04
    • 2023-03-09
    • 2014-05-03
    • 2012-11-16
    • 1970-01-01
    相关资源
    最近更新 更多