T-SQL 多语句表值函数
Posted
技术标签:
【中文标题】T-SQL 多语句表值函数【英文标题】:T-SQL Multi-Statement Table-Valued Function 【发布时间】:2013-10-03 19:49:09 【问题描述】:我真的需要一些帮助来编写一个使用以下逻辑的多语句表值函数:
接受 varchar 参数作为输入 如果参数以 A 开头,则运行 select 语句 如果没有返回行,则运行 select 语句 如果参数不以A开头,则运行select语句 如果没有返回行,则运行 select 语句 返回一个输出表,该表将是上面的结果集之一,具体取决于参数到目前为止,这就是我所拥有的:
CREATE FUNCTION dbo.CheckAccess
(@UserName varchar(30))
RETURNS @AccessTable TABLE (User varchar(max), Access varchar(max))
AS
BEGIN
IF LEFT(@UserName,1) = 'A'
INSERT INTO @AccessTable
SELECT
CASE
WHEN EXISTS (SELECT User, Access FROM dbo.AccessTable1 WHERE User = @UserName)
THEN (SELECT User, Access FROM dbo.AccessTable1 WHERE User = @UserName)
ELSE (SELECT @UserName User, 'No Access' Access)
END
ELSE
INSERT INTO @AccessTable
SELECT
CASE
WHEN EXISTS (SELECT User, Access FROM dbo.AccessTable2 WHERE User = @UserName)
THEN (SELECT User, Access FROM dbo.AccessTable2 WHERE User = @UserName)
ELSE (SELECT @UserName User, 'No Access' Access)
END
RETURN
END;
不确定我在这里遗漏了什么,但我收到以下错误:
Msg 116, Level 16, State 1, Procedure CheckAccess, Line 90
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
Msg 116, Level 16, State 1, Procedure CheckAccess, Line 92
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
Msg 213, Level 16, State 1, Procedure CheckAccess, Line 11
Column name or number of supplied values does not match table definition.
我知道如何在存储过程中使用临时表相当容易地做到这一点,但是由于它们不是函数中的选项,所以我遇到了一些困难。如果有人可以提供一些建议,我将不胜感激。提前致谢。
【问题讨论】:
【参考方案1】:您可以使用@@rowcount
服务器变量将函数简化为:
CREATE FUNCTION dbo.CheckAccess
(@UserName varchar(30))
RETURNS @AccessTable TABLE (User varchar(max), Access varchar(max))
AS
BEGIN
IF LEFT(@UserName,1) = 'A'
INSERT INTO @AccessTable
SELECT User, Access FROM dbo.AccessTable1 WHERE User = @UserName
ELSE
INSERT INTO @AccessTable
SELECT User, Access FROM dbo.AccessTable2 WHERE User = @UserName
--@@rowcount gives number of records inserted/affected from immediately previous query
IF @@RowCount = 0
INSERT INTO @AccessTable
SELECT @UserName User, 'No Access' Access
RETURN
END;
【讨论】:
【参考方案2】:而不是像这样的布尔检查
EXISTS (SELECT User, Access FROM dbo.AccessTable1 WHERE User = @UserName)
试试
EXISTS (SELECT 1 FROM dbo.AccessTable1 WHERE User = @UserName)
一般来说,EXISTS 表达式不需要特定的结果,它只需要检查是否返回 NULL,因为找不到任何行,或者无论是什么都可以返回一些东西。这是一个布尔表达式,计算结果为是或否。 '1' 就足够了。前两条错误消息就是关于这个的。
下一个问题是 CASE 表达式根据定义只能定义一个字段和一个字段。它无法返回所需的两个字段。这就是最后一条错误消息的含义,该函数被定义为返回两个字段。您现在可以编写两个用逗号分隔的 CASE 表达式。
不过,我会为您的逻辑建议一种不同的方法:在您的 IF 语句中执行子 IF,例如嵌套的 IF。这个我没有测试过,只是一个想法:
IF LEFT(@UserName,1) = 'A'
IF EXISTS (SELECT 1 FROM dbo.AccessTable1 WHERE User = @UserName)
INSERT INTO @AccessTable
SELECT User, Access FROM dbo.AccessTable1 WHERE User = @UserName
ELSE (SELECT @UserName User, 'No Access' Access)
ELSE
IF EXISTS (SELECT 1 FROM dbo.AccessTable2 WHERE User = @UserName)
INSERT INTO @AccessTable
SELECT User, Access FROM dbo.AccessTable2 WHERE User = @UserName
ELSE (SELECT @UserName User, 'No Access' Access)
或另一个可能表现更好的想法,但我不确定这是否满足您对“访问”字段 100% 的要求。如果@username 出现在表中,那么总是会在 Access 字段中显示内容吗?
IF LEFT(@UserName,1) = 'A'
SELECT
ISNULL(User,@UserName) User
,ISNULL(Access,'No Access') Access
FROM dbo.AccessTable1 WHERE User = @UserName
ELSE
SELECT
ISNULL(User,@UserName) User
,ISNULL(Access,'No Access') Access
FROM dbo.AccessTable2 WHERE User = @UserName
补充一点:IF(也是 ELSE)只会考虑以下一个语句。如果要运行多个语句,则需要像这样通过 BEGIN 和 END 封装它们
IF @fact=1
BEGIN
statement 1
.
.
statement n
END
ELSE
BEGIN
statement 1
.
.
statement n
END
【讨论】:
以上是关于T-SQL 多语句表值函数的主要内容,如果未能解决你的问题,请参考以下文章