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

时间:2009-07-20 17:09:55

标签: sql stored-procedures function logic cursors

我目前正在处理一个遗留应用程序,并继承了一些阴暗的SQL。该项目从未投入生产,但现在正在实施。在初始测试期间,我发现了一个错误。应用程序调用存储过程,该存储过程调用许多其他存储过程,创建游标,循环游标以及许多其他内容。 FML。

目前设计应用程序的方式,它调用存储过程,然后使用一组新数据重新加载UI。当然,我们想要显示的数据仍在SQL服务器端处理,因此显示时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在完成对[ALLOCATED_BUDGET]存储过程的主调用之前等待吗?

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

非常感谢任何反馈。我有一种感觉,我在使用SQL函数方面是正确的,但不是100%肯定。

**其他信息:

  1. 执行代码在连接字符串
  2. 中使用[async = true]
  3. 执行代码使用[SqlCommand]。[ExecuteNonQuery]方法

6 个答案:

答案 0 :(得分:2)

您还可以尝试在子存储过程中使用RETURN statement,这可用于将结果代码返回给父过程。您可以通过“exec @myresultcode = BUDGET_ALLOCATE_SCENARIO_REGIONBYREGION()”之类的内容调用子过程。我认为这应该强制父进程等待子进程完成。

答案 1 :(得分:2)

你是怎么称呼这个程序的?我猜你正在使用ExecuteNonQuery()来调用该过程。尝试使用ExecuteScalar()调用该过程,并修改如下所示的过程:

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

    RETURN True
END

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

答案 2 :(得分:2)

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

事实上,我会说我不相信这种情况正在发生。如果您发现用户界面与您认为SP应该做的事情之间存在差异,那么我认为它有不同的原因。

连接字符串中是否包含async = true?是使用BeginExecuteReader还是Begin-anything执行SP?

答案 3 :(得分:0)

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

您可以从UI查询此内容,以查看是否通过轮询此状态代码来完成任务。

答案 4 :(得分:0)

  

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

没有

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

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

答案 5 :(得分:0)

就个人而言,我会更关心更换这些游标而不是将其转换为函数。

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

还要考虑这是否应该都在一个事务中(这些proc是否在表中更改数据?)

(我是唯一一个发现它很有趣的人,你有一个proc来运行什么都不做的过程?)