代码之家  ›  专栏  ›  技术社区  ›  D3vtr0n

SQL用户定义函数与存储过程分支

  •  1
  • D3vtr0n  · 技术社区  · 15 年前

    我目前正在开发一个遗留应用程序,并用它继承了一些可疑的SQL。这个项目从未投入生产,但现在正在进行中。在最初的测试中,我发现了一个错误。应用程序调用一个存储过程,该存储过程调用许多其他存储过程、创建光标、通过光标进行循环以及许多其他操作。FML。

    目前,应用程序的设计方式是调用存储过程,然后用一组新的数据重新加载UI。当然,我们要显示的数据仍在SQL Server端处理,因此显示时UI结果不完整。为了解决这个问题,我只是在加载UI之前让线程休眠30秒。这是一个可怕的黑客,我想在SQL方面正确地解决这个问题。

    我的问题是…是否值得将分支存储过程转换为函数?这会使主线存储过程在处理之前等待返回值吗?

    以下是存储过程:

        ALTER PROCEDURE [dbo].[ALLOCATE_BUDGET] 
        @budget_scenario_id uniqueidentifier
    AS
    BEGIN
        -- SET NOCOUNT ON added to prevent extra result sets from
        -- interfering with SELECT statements.
        SET NOCOUNT ON;
    
        DECLARE @constraint_type varchar(25)
    
        -- get project cache id and constraint type
        SELECT @constraint_type = CONSTRAINT_TYPE
        FROM BUDGET_SCENARIO WHERE BUDGET_SCENARIO_ID = @budget_scenario_id
    
        -- constraint type is Region by Region
        IF (@constraint_type = 'Region by Region')
          EXEC BUDGET_ALLOCATE_SCENARIO_REGIONBYREGION @budget_scenario_id
    
        -- constraint type is City Wide
        IF (@constraint_type = 'City Wide')
          EXEC BUDGET_ALLOCATE_SCENARIO_CITYWIDE @budget_scenario_id
    
        -- constraint type is Do Nothing
        IF (@constraint_type = 'Do Nothing')
          EXEC BUDGET_ALLOCATE_SCENARIO_DONOTHING @budget_scenario_id
    
        -- constraint type is Unconstrained
        IF (@constraint_type = 'Unconstrained')
          EXEC BUDGET_ALLOCATE_SCENARIO_UNCONSTRAINED @budget_scenario_id
    
        --set budget scenario status to "Allocated", so reporting tabs in the application are populated
        EXEC BUDGET_UPDATE_SCENARIO_STATUS @budget_scenario_id, 'Allocated'
    END
    

    为了避免在调用的.NET应用程序UI中显示不完整的结果集,在分支调用中的游标完成之前,将这些存储过程转换为具有返回值的函数是否值得?这会强制SQL在完成对[已分配的预算]存储过程的主调用之前等待吗?

    • 存储过程中的最后一个SQL语句调用将状态设置为“已分配”。这发生在前一个调用中的光标完成处理之前。将这些调用转换为函数调用会影响存储过程如何将焦点返回给应用程序吗?

    非常感谢您的任何反馈。我觉得我使用SQL函数是正确的,但不是百分之百确定。

    **附加信息:

    1. 执行代码时在连接字符串中使用[async=true]
    2. 执行代码使用[sqlcommand]。[executeNonQuery]方法
    6 回复  |  直到 15 年前
        1
  •  2
  •   Chris Porter    15 年前

    你怎么叫这个程序?我猜您正在使用executeNonQuery()调用该过程。尝试使用executescalar()调用该过程,并按如下方式修改该过程:

    ALTER PROCEDURE [dbo].[ALLOCATE_BUDGET] 
        @budget_scenario_id uniqueidentifier
    AS
    BEGIN
       ...
    
        RETURN True
    END
    

    这将导致.NET中的数据执行代码在继续之前等待过程完成。如果不希望用户界面在过程执行期间“挂起”,请使用BackgroundWorkerProcess或类似的方法在单独的线程上运行查询,并查找完成的回调,以使用结果更新用户界面。

        2
  •  2
  •   tbreffni    15 年前

    您也可以尝试使用 RETURN statement 在子存储过程中,可以使用该存储过程将结果代码返回给父过程。您可以通过以下方式调用子过程: exec @myresultcode = BUDGET_ALLOCATE_SCENARIO_REGIONBYREGION() “。我认为这应该强制父过程等待子过程完成。

        3
  •  2
  •   John Saunders    15 年前

    我从未听说存储过程在后台执行时可能返回调用方。

    事实上,我会尽量说我不相信会发生这种事。如果您看到了UI和您认为SP应该做的事情之间的区别,那么我相信它有不同的原因。

    连接字符串中是否有async=true?sp是使用beginExecuteReader执行的还是开始其他操作?

        4
  •  0
  •   shahkalpesh    15 年前

    冒着听起来很简单的风险,我建议您创建一个可以存储存储过程状态的表。不知何故,可以指示整个流程和子流程已完成执行的标志。

    您可以从UI中查询这个,以查看是否通过轮询此状态代码完成了这些操作。

        5
  •  0
  •   Amy B    15 年前

    将这些调用转换为函数调用会影响存储过程如何将焦点返回给应用程序吗?

    不。

    存储过程不知道其调用方是UI应用程序。存储过程中没有任何可以影响UI应用程序行为的内容。

    很可能UI应用程序正在一个连接上调用存储过程,然后在另一个连接上刷新其数据。有很多方法可以让UI延迟刷新,但是我要推的是应该有一个单独的数据库连接。

        6
  •  0
  •   John Saunders    15 年前

    就个人而言,我更关心的是替换那些光标,而不是将其转换为函数。

    在检查前一个进程的有效返回代码之前,我不会运行最后一个进程(如果前一个进程中的一个进程死了,这件事就真的很麻烦了!)

    还要考虑这是否都应该在事务中(这些进程是否更改表中的数据?)

    (我是唯一一个觉得有趣的人吗?你有一个程序来运行这个程序,不做任何事情?)