Cha*_*ace 8 sql-server functions recursive
TL;博士; SQL Server 允许标量 UDF 在架构绑定时递归调用自身,但仅在使用语法进行更改时才这样做,这是否是一个错误CREATE OR ALTER
?或者是其他语法被禁止的错误?
一个简单的递归标量 UDF 可以构造如下
CREATE FUNCTION dbo.Try1 (@i int)
RETURNS int
AS BEGIN
RETURN IIF(@i = 0, 0, @i + dbo.Try1(@i - 1));
END;
Run Code Online (Sandbox Code Playgroud)
只要这不是架构绑定的,那么这是允许的。
让我们尝试模式绑定它,我们会做
CREATE FUNCTION dbo.Try2 (@i int)
RETURNS int
WITH SCHEMABINDING
AS BEGIN
RETURN IIF(@i = 0, 0, @i + dbo.Try2(@i - 1));
END;
Run Code Online (Sandbox Code Playgroud)
没有。
Cannot find either column "dbo" or the user-defined function
or aggregate "dbo.Try2", or the name is ambiguous
Run Code Online (Sandbox Code Playgroud)
不使用递归创建它然后更改它
CREATE OR ALTER FUNCTION dbo.Try3 (@i int)
RETURNS int
WITH SCHEMABINDING
AS BEGIN RETURN NULL; END;
Run Code Online (Sandbox Code Playgroud)
ALTER FUNCTION dbo.Try3 (@i int)
RETURNS int
WITH SCHEMABINDING
AS BEGIN
RETURN IIF(@i = 0, 0, @i + dbo.Try3(@i - 1));
END;
Run Code Online (Sandbox Code Playgroud)
这次出现了不同的错误:
Cannot schema bind function 'dbo.Try3' because name 'dbo.Try3' is invalid
for schema binding. Names must be in two-part format
and an object cannot reference itself.
Run Code Online (Sandbox Code Playgroud)
嗯,an object cannot reference itself
谁发明了这条规则?它不在文档中。
让我们尝试一下CREATE OR ALTER
CREATE OR ALTER FUNCTION dbo.Try4 (@i int)
RETURNS int
WITH SCHEMABINDING
AS BEGIN
RETURN IIF(@i = 0, 0, @i + dbo.Try4(@i - 1));
END;
Run Code Online (Sandbox Code Playgroud)
还没。
但是如果我们首先CREATE
不使用递归,然后使用CREATE OR ALTER
(不 ALTER
)使用递归,那么它就可以工作
CREATE OR ALTER FUNCTION dbo.Try5 (@i int)
RETURNS int
WITH SCHEMABINDING
AS BEGIN RETURN NULL; END;
Run Code Online (Sandbox Code Playgroud)
CREATE OR ALTER FUNCTION dbo.Try5 (@i int)
RETURNS int
WITH SCHEMABINDING
AS BEGIN
RETURN IIF(@i = 0, 0, @i + dbo.Try5(@i - 1));
END;
Run Code Online (Sandbox Code Playgroud)
奇怪的是:无论哪种方式CREATE OR ALTER
在底层工作,这都是没有意义的。如果它确实删除并重新创建,那么为什么我们没有得到第一个错误呢?如果它改变了,那么为什么最后一个选项会起作用呢?
最有趣的是:如果我们首先在没有模式绑定的情况下创建它,那么CREATE OR ALTER WITH SCHEMABINDING
我们会得到
Cannot schema bind function 'dbo.Try6'. 'dbo.Try6' is not schema bound.
Run Code Online (Sandbox Code Playgroud)
这完全是无稽之谈。
一般而言,自引用函数没有很好的文档记录,但对此类函数的模式绑定的限制一直存在。父语法页面中并未提及所有错误情况。
问题中概述的导致模式绑定自引用函数的特定事件顺序不应允许(它也适用于多语句表值函数)。
允许自引用函数的模式绑定引入了许多必须考虑和测试的新可能性。例如,对函数的以下使用会导致DBCC CHECKTABLE
失败:
CREATE TABLE dbo.Test
(
n integer NOT NULL,
-- Can be persisted because the function is deterministic
-- Checks for determinism require schemabinding
sn AS dbo.Try5(n) PERSISTED,
CHECK (sn > 0)
);
-- Succeeds
INSERT dbo.Test (n)
VALUES (31);
DBCC CHECKTABLE (N'dbo.Test')
WITH EXTENDED_LOGICAL_CHECKS;
Run Code Online (Sandbox Code Playgroud)
CREATE TABLE dbo.Test
(
n integer NOT NULL,
-- Can be persisted because the function is deterministic
-- Checks for determinism require schemabinding
sn AS dbo.Try5(n) PERSISTED,
CHECK (sn > 0)
);
-- Succeeds
INSERT dbo.Test (n)
VALUES (31);
DBCC CHECKTABLE (N'dbo.Test')
WITH EXTENDED_LOGICAL_CHECKS;
Run Code Online (Sandbox Code Playgroud)
我没有调查此失败的原因,但我认为CHECKTABLE
验证计算列值的活动最终超出了最大嵌套级别 32。
许多事情需要测试和/或调整以支持模式绑定自引用功能。这种用法还不够流行,不足以证明投资的合理性。SQL Server 中存在递归的替代方案。
归档时间: |
|
查看次数: |
501 次 |
最近记录: |