如何使此存储过程(SQL Server)易于阅读?

时间:2019-02-20 19:32:11

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

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

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

有人知道编写此代码的可读性更高的方法吗?如果我的问题没有道理,那么我将重述一下。谢谢。

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在这个线程上讨论的一个附带问题:   我在下面添加包含内联表值函数的代码。我的巨大查询有几个局部变量。下面是伪代码。代码导致错误。

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
)

4 个答案:

答案 0 :(得分:2)

使您庞大的查询成为一个视图

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

答案 1 :(得分:1)

您提到了这一点

  

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

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

因此,您的存储过程实际上会变得和现在一样短:

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');

答案 2 :(得分:0)

您可以使用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

优势

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

缺点

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

答案 3 :(得分:0)

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

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