【问题标题】:How can I make this stored procedure (SQL Server) easier to read?如何使这个存储过程 (SQL Server) 更易于阅读?
【发布时间】:2019-02-20 19:32:10
【问题描述】:

下面是我当前存储过程的伪代码。首先,我有一个创建临时表的巨大查询。然后,我在存储过程中有其他查询正在查询该临时表。

我的目标是让我的存储过程更具可读性。巨大的查询使它变得困难,因为它占用了太多空间。我已经尝试为这个巨大的查询创建一个单独的存储过程来创建一个临时表,但是无法在其他存储过程之外访问临时表。

有谁知道编写此代码的更易读的方式?如果我的问题没有意义,那么我会改写它。谢谢。

Alter Procedure spMyStoredProc
Begin
    --Value of 1 for each param means I want to execute the query
    @sqlQueryA Bit = 0,
    @sqlQueryB Bit = 0,
    @sqlQueryC Bit = 0

    Select Columns
    Into #MyTempTable
    From **HUGE Query**

    If @sqlQueryA = 1 
    Begin    
        Select * From #MyTempTable
    End
    Else If @sqlQueryB = 1
       ... 
    Else If @sqlQueryC = 1
    Begin
        Query something else from #MyTempTable
    End
    Else
        Return
End

以下是 Evaldas Buinauskas 和我在此线程上讨论的一个附带问题: 我在下面添加了包含内联表值函数的代码。我的 HUGE 查询有几个局部变量。下面是伪代码。该代码导致错误。

CREATE FUNCTION fn_myFunction()
RETURNS TABLE
AS
RETURN
(
    --Declaration is not allowed
    Declare @myLocalVar As DateTime
    Set @myLocalVar = '2019-01-10'

    #HUGE Query
    Where SomeColumn = @myLocalVar
)

【问题讨论】:

  • 问题:使它可读的问题是什么?使用间距/cmets 使其更清洁。您可以将较大的查询分离到它自己的 SP 中,并在 temp db 之外使用一个永久表并将其命名为 StagingSomething,但除非您在其他地方使用它,否则它会变得更加复杂。
  • 这并不是一种更易读的方式,但它的性能有时会很糟糕,而其他时候则完全没问题。您需要考虑对此进行一些修改。 sqlinthewild.co.za/index.php/2009/09/15/…
  • 我不是粉丝,但你看过 Insert-Exec blog.sqlauthority.com/2013/05/27/…
  • 可读性不如性能重要,你同意吗?我不会为了确定从中选择什么而将大量查询包含在临时表中的多种可能性。相反,我会创建一个参数化该查询,并在需要时将其嵌套在 proc 中。
  • 小字体?但说真的,将庞大的查询设为视图会将其移出您的存储过程。有些人不喜欢这种方法,但我认为没有问题

标签: sql sql-server stored-procedures temp-tables code-readability


【解决方案1】:

让您的大型查询成为一个视图

Select *
Into #MyTempTable
From MyView

此外,由于您的查询似乎是互斥的,因此您不需要三位。

传递单个值、字符串或枚举值以检查要运行哪个查询,然后通过返回进行短路。

IF @Query = 'QueryA'
BEGIN
 Select QueryA From #MyTempTable
RETURN 1;
END;

IF @Query = 'QueryB'
BEGIN
 Select QueryB From #MyTempTable
RETURN 1;
END;

--throw an error if the query is not found

【讨论】:

  • 这将解决大多数人的问题。在我最初的问题中,我没有提到我的 HUGE 查询有几个局部变量。视图中不允许使用局部变量。谢谢,这帮助我了解了更多关于 Views 的信息!
  • 我也做了你推荐的改变。我没有将多个参数作为 Bit 类型,而是创建了一个变量并将一个字符串传递给它。每个字符串代表临时表的一个查询。
【解决方案2】:

你提到了这个:

我的目标是让我的存储过程更具可读性。巨大的查询使它变得困难,因为它占用了太多空间。我已经尝试为这个庞大的查询创建一个单独的存储过程来创建一个临时表,但是在该其他存储过程之外无法访问该临时表。

根据您的查询是否有参数,我可能会将该查询包装到视图或内联表值函数中以隔离它。

所以你的存储过程就会变得和现在一样短:

ALTER PROCEDURE spMyStoredProc
BEGIN
    SET NOCOUNT ON;

    -- Value of 1 for each param means I want to execute the query
    @sqlQueryA BIT = 0,
    @sqlQueryB BIT = 0,
    @sqlQueryC BIT = 0,

    SELECT Columns
    INTO #MyTempTable
    FROM dbo.ViewOrInlineValuedFunction

    IF @sqlQueryA = 1
    BEGIN
        SELECT *
        FROM #MyTempTable
    END;
    ELSE IF @sqlQueryB = 1
    BEGIN
        SELECT *
        FROM #MyTempTable;
    END;
    ELSE IF @sqlQueryC = 1
    BEGIN
        SELECT *
        FROM #MyTempTable
    END;
END;

你不能修改函数来接受参数吗? :)

CREATE FUNCTION fn_myFunction(@myLocalVar DATE)
RETURNS TABLE
AS
RETURN (
    SELECT *
    FROM HugeQuery
    WHERE SomeColumn = @myLocalVar
);

那么函数调用就可以这么简单地调用:

SELECT *
FROM dbo.fn_myFunction('2019-01-10');

【讨论】:

  • 既然我的 HUGE 查询有局部变量,那么看来我需要使用多语句表值函数。我还在努力。我能够获得“插入执行”的工作方式。我在下面添加了。感谢您的帮助!
  • 多语句表值函数可以正常工作。请记住,您希望将其结果限制为 1000 行,因为表值函数返回一个表变量,该变量符合此限制。
  • 感谢您告诉我。我的 HUGE 查询返回 8000 行。我的 HUGE 查询也是一个 Select 语句。我收到一条消息说“函数中包含的选择语句无法将数据返回给客户端。”没关系。我得到了我需要的结果并学习了一些关于 SQL Server 的新知识。再次感谢。
  • 可以将您的查询转换为适合在线表值函数的内容。你介意用它更新你的问题吗?
  • 我刚刚为内联表值函数添加了我的伪代码。我将其添加到原始问题中。
【解决方案3】:

您可以使用INSERT EXEC 语句。

Alter Procedure spMyStoredProc
Begin
    --Value of 1 for each param means I want to execute the query
    @sqlQueryA Bit = 0,
    @sqlQueryB Bit = 0,
    @sqlQueryC Bit = 0

    Insert Into #MyTempTable
    Exec spHugeQuery --here you execute the stored proc that selects from huge query 

    If @sqlQueryA = 1 
    Begin    
        Select * From #MyTempTable
    End
    Else If @sqlQueryB = 1
       ... 
    Else If @sqlQueryC = 1
    Begin
        Query something else from #MyTempTable
    End
    Else
        Return
End

优势

此解决方案最符合您的原始解决方案,如果您需要设置要在查询中使用的变量,它将很好地工作。

缺点

存储过程spHugeQuery 需要返回正确的列数和可以插入到临时表中的正确数据类型。如果您的临时表定义或存储过程中的 select 语句发生了变化,您将不会知道,直到它在运行时失败。

【讨论】:

  • 我想使用这个解决方案,但我又回到了我原来问题上的代码。 Insert-Exec 对我在临时表上的一些查询有效,但其他查询执行得非常糟糕。使用 Like 关键字的查询不可用。
【解决方案4】:

Evaldas Buinauskas 的想法最终成为最适合我的答案。它解决了可读性问题,局部变量问题,并且表现良好。请注意,我将 HUGE 查询移到了内联表值函数中。您可以在下面的代码中看到它被调用。我将本地变量作为参数传递给函数。该函数创建了我需要的临时表。

Alter Procedure spMyStoredProc
Begin

@SqlAsParam Nvarchar(100),
@otherParam DataType,
…

Declare @localVarA DataType
Set @localVarA = value

Declare @localVarB DataType
Set @localVarB = value  

Select * 
Into #MyTempTable
From dbo.fn_GetHUGEquery(@localVarA, @localVarB)

If @SqlAsParam = 'sqlQueryA'
  Begin    
     Select * From #MyTempTable
  End
Else If @SqlAsParam = 'sqlQueryB'
       ... 
Else If @SqlAsParam = 'sqlQueryC'
  Begin
      Query something else from #MyTempTable
  End
Else
     Return
End

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多