执行存储过程内联,类似于 UDF?

Posted

技术标签:

【中文标题】执行存储过程内联,类似于 UDF?【英文标题】:Execute a Stored Procedure Inline, similar to a UDF? 【发布时间】:2013-02-07 12:38:56 【问题描述】:

我有一个类似这样的结构:

Company
(
  CompanyID
  CompanyLastTransactionNo
)

Transaction
(
  TransactionID
  CompanyID
  CompanyTransactionNo
  TransactionAmount
)

那么我有一个程序可以执行以下操作:

INSERT INTO Transaction
(CompanyID, CompanyTransactionNo, TransactionAmount)
SELECT 
   CompanyID,
   fn_GetNextCompanyTrancationNo(CompanyID),
   TransactionAmount
FROM
   LoadingTable


CREATE FUNCTION [dbo].[fn_GetNextCompanyTrancationNo]
(
 @CompanyID CHAR(10)
)
RETURNS INT
AS
BEGIN
    DECLARE @trxno int
           DECLARE @trxnoNew int

    SELECT @trxno = CompanyLastTransactionNo
    FROM dbo.Company
    WHERE ID = @CompanyID;

    SET @trxnoNew = @trxno + 1;

    UPDATE dbo.Company
    SET CompanyLastTransactionNo = @trxnoNew
    WHERE CompanyID = @CompanyID;


    RETURN @trxno

END

编译时我得到:

消息 443,级别 16,状态 15,过程 fns_fn_GetNextCompanyTrancationNo,第 19 行 在函数中无效使用副作用运算符“UPDATE”。

呃。完全忘记了。

所以这是我的问题,有没有办法将存储过程用作内联函数,类似于这个?也许这是一个不好的方法?

我有点卡在我的表上,或者我会使用一个序列来获取下一个数字?

【问题讨论】:

您提到序列:您使用的是 SQL Server 2012 吗? 不,使用 2008 R2。是的,我知道序列要到 2012 年才可用。但我应该澄清一下。现在是 2008R2。 【参考方案1】:

这是个坏主意。具有副作用的 UDF 的问题是您无法控制在 select 语句的上下文中何时/如何调用它。

考虑以下几点:

CREATE TABLE t (id INT )
INSERT INTO t (id) values (1)
INSERT INTO t (id) values (2)
INSERT INTO t (id) values (3)
INSERT INTO t (id) values (4)
INSERT INTO t (id) values (5)
INSERT INTO t (id) values (6)
INSERT INTO t (id) values (7)
INSERT INTO t (id) values (8)
INSERT INTO t (id) values (9)
INSERT INTO t (id) values (10)

SELECT id, dbo.myUDF() FROM t WHERE t.id <= 3 and dbo.myUDF() = @someValue

myUDF() 被调用了多少次? 10? 3? 13?还是20?

具体来说,SQL 语言标准中没有规定应用谓词的顺序。

【讨论】:

嗯。我希望这样做,坦率地说,如果这是在 UDF 中禁止副作用的唯一原因,这是一个可怕的原因。任何 SQL 实现中都有各种各样的东西以未定义的顺序执行,我们使用它们。我想做的只是SELECT id, dbo.myUDF(id) FROM t。我会用一个过程循环执行它,但这会更干净。

以上是关于执行存储过程内联,类似于 UDF?的主要内容,如果未能解决你的问题,请参考以下文章

从 UDF 执行存储过程

面试概率极大的Oracle存储过程

我们应该在 Redshift 的存储过程中使用 udf

可以从雪花中的函数调用存储过程吗

存储过程

SQL入门经典 之自定义函数