1

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

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

我知道如何在存储过程中使用临时表相当容易地做到这一点,但是由于它们不是函数中的选项,所以我遇到了一些困难。如果有人可以提供一些建议,我将不胜感激。提前致谢。

4

2 回答 2

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;
于 2013-10-03T20:50:11.430 回答
0

而不是像这样的布尔检查

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 出现在表中,那么访问字段中是否总是内容?

   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
于 2013-10-03T20:35:32.947 回答