【问题标题】:Find the value of a record an return it back from stored procedure查找记录的值并将其从存储过程中返回
【发布时间】:2019-06-04 15:58:53
【问题描述】:

我创建了一个存储过程,它接受表中唯一项的值并在该表中搜索它。如果存在,则返回该行的主键列的值。如果它不存在,则暂时返回 1234 以进行测试。

我就是这么写的:

CREATE PROCEDURE dbo.MyTestSP
    @ExID VARCHAR(64)
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @ExIDPK INT;

    SELECT  @ExIDPK = ExPK
    FROM 
        dbo.EXIDs
    WHERE 
        EXISTS(SELECT 1 FROM dbo.EXIDs WHERE ExID = @ExID);

    IF @ExID IS NOT NULL
    BEGIN
        RETURN @ExIDPK;
    END;
    ELSE
    BEGIN
        RETURN 1234;
    END;
END;

这是为了测试我如何称呼它:

EXEC MyTestSP 'ewedweweewe';

但它总是返回这个:

程序试图返回 NULL 状态,这是不允许的。将返回状态 0。

我在这里做错了什么?

【问题讨论】:

  • 为什么在WHERE 子句中使用EXISTS()?为什么不直接选择 PK 或使用 OUTPUT 参数?
  • 我的意思是,您正在使用:IF @ExID IS NOT NULL,并且您知道它不为空,因为您正在给它一个值。并不意味着您给它的值在 dbo.ExIDs 表上匹配...所以 @ExIDPK 可能为空
  • 另外,你在END; 中有一个分号,这是错误的,你根本不需要IF,只需简单化并将变量的默认值设置为 1234。

标签: sql sql-server tsql


【解决方案1】:

查看您的过程,您将变量声明为DECLARE @ExIDPK INT;,因此默认值为NULL。如果传递的值在您的表中不存在,这会使您的 SP 返回 NULL,这就是您收到此消息的原因。

另外,不需要在 where 子句中使用EXISTS(),因为你有参数,只需简单的检查就可以了。在IFEND 中有一个额外的分号

IF @ExID IS NOT NULL -- you are checking the wrong variable here too
BEGIN
    RETURN @ExIDPK;
END;
ELSE
BEGIN
    RETURN 1234;
END;--This one

这是错误的,你根本不需要IF,只需简单点

CREATE PROCEDURE dbo.MyTestSP
    @ExID VARCHAR(64)
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @ExIDPK INT = 1234; --Will ensure your variable never be NULL

    SELECT  @ExIDPK = ExPK
    FROM 
        dbo.EXIDs
    WHERE ExID = @ExID;

        RETURN @ExIDPK;

END;

这将确保您的变量永远不会是NULL,因为您设置了默认值,如果您的查询不返回任何行(0 行),该值不会更改。

最后,我建议使用 OUTPUT 参数(甚至是 SELECT)而不是使用 RETURN 代码。

返回码通常用于过程中的流程控制块中,用于为每种可能的错误情况设置返回码值

Return Data from a Stored Procedure

【讨论】:

    【解决方案2】:

    由于问题是基于理解返回值的机制提出的,因此我将把它作为一种首选机制来发布。通常返回代码/返回值是为错误代码保留的,0 表示成功,非 0 表示成功以外的内容(值得注意的例外是 SQL Server 代理 run_status。

    下面的代码示例将允许您测试不同的场景:

    if object_id(N'[test].[table_01]', N'U') is not null
      drop table [test].[table_01];
    
    go
    
    create table [test].[table_01]
      (
         [id]      [int] identity(1, 1) not null,
              constraint [test__table_01__id__pk] primary key clustered([id])
         , [value] varchar(64)
      );
    
    go
    
    insert into [test].[table_01]
                ([value])
    values      ('red'),
                ('green'),
                ('blue');
    
    go
    
    if object_id(N'[test].[get__name__id]', N'P') is not null
      drop procedure [test].[get__name__id];
    
    go
    
    create procedure [test].[get__name__id] @value varchar(64)
                                            , @id  [int] = null output
    as
      begin
          set transaction isolation level read uncommitted;
          set NOCOUNT on;
    
          select @id = [id]
          from   [test].[table_01]
          where  [value] = @value;
      end;
    
    go
    
    --
    declare @pk      [int]= null
            , @value [varchar](64)='test';
    
    execute [test].[get__name__id]
      @value=@value
      , @id=@pk output;
    
    if @pk is not null
      begin
          select @pk      as [primary_key__for__value]
                 , @value as [value];
      end;
    else
      begin
          select 'No primary key found for value ' + @value;
      end; 
    

    【讨论】:

      【解决方案3】:

      几件事。

      • 您的 if 检查错误。您正在检查 @ExID 而不是 @ExIDPK@ExID 根据您的 proc 定义不能为空

      • 我建议您也将exist 逻辑更改为更简单的where 子句

      见下面的代码

      CREATE PROCEDURE dbo.MyTestSP
          @ExID VARCHAR(64)
      AS
      BEGIN
          SET NOCOUNT ON;
          DECLARE @ExIDPK INT;
      
          SELECT  @ExIDPK = ExPK
          FROM 
              dbo.EXIDs
          WHERE ExID = @ExID;
      
              RETURN ISNULL(@ExIDPK,1234);
      
      END;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-18
        • 1970-01-01
        • 1970-01-01
        • 2015-10-22
        • 2019-04-20
        • 2020-04-24
        • 1970-01-01
        • 2017-05-06
        相关资源
        最近更新 更多