T-SQL多语句表值函数

时间:2013-10-03 19:49:09

标签: tsql sql-server-2008-r2 user-defined-functions table-valued-parameters

我真的可以使用一些帮助来编写一个使用以下逻辑的多语句表值函数:

  • 接受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.

我知道如何使用临时表在存储过程中相当容易地完成此操作,但由于它们不是函数中的选项,因此我遇到了一些困难。如果有人能提出一些建议,我真的很感激。提前谢谢。

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分:0)

而不是像这样的布尔检查

EXISTS (SELECT User, Access FROM dbo.AccessTable1 WHERE User = @UserName)

EXISTS (SELECT 1 FROM dbo.AccessTable1 WHERE User = @UserName)

一般来说EXISTS表达式不需要特定的结果,它只需要检查是否返回了NULL,因为没有找到行或者无论是什么都可以返回。它是一个布尔表达式,其值为yes或no。 '1'足以满足这一目的。前两个错误消息是关于此的。

下一个问题是CASE表达式根据定义只能定义一个字段和一个字段。它无法返回所需的两个字段。这是最后一条错误消息的可能性,该函数被定义为返回两个字段。您现在可以用逗号分隔两个CASE表达式。

我建议你的逻辑采用不同的方法:在你的IF语句中做sub-IFs,比如嵌套的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)

或其他可能表现更好的想法,但我不确定这是否符合您对“Access”字段100%的要求。如果表中存在@username,那么 allways 是否在Access-field中是否满足?

   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