Sql 查找记录的值并从存储过程返回该值

Sql 查找记录的值并从存储过程返回该值,sql,sql-server,tsql,Sql,Sql Server,Tsql,我创建了一个存储过程,它从我的表中接受唯一项的值,并在该表中搜索它。如果存在,返回该行主键列的值。如果它不存在,那么现在就返回1234进行测试 我就是这样写的: CREATE PROCEDURE dbo.MyTestSP @ExID VARCHAR(64) AS BEGIN SET NOCOUNT ON; DECLARE @ExIDPK INT; SELECT @ExIDPK = ExPK FROM dbo.EXIDs WHE

我创建了一个存储过程,它从我的表中接受唯一项的值,并在该表中搜索它。如果存在,返回该行主键列的值。如果它不存在,那么现在就返回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的状态

我做错了什么?

两件事

  • 如果你的支票错了。您正在检查
    @ExID
    而不是
    @ExIDPK
    @ExID
    根据您的过程定义不能为空

  • 我建议您将
    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;
两件事

  • 如果你的支票错了。您正在检查
    @ExID
    而不是
    @ExIDPK
    @ExID
    根据您的过程定义不能为空

  • 我建议您将
    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;

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

此外,在where子句中不需要使用
EXISTS()
,因为您有参数,只需进行简单的检查即可。如果
IF

IF @ExID IS NOT NULL -- you are checking the wrong variable here too
BEGIN
    RETURN @ExIDPK;
END;
ELSE
BEGIN
    RETURN 1234;
END;--This one
这是错误的,您根本不需要
,如果
,只需将其简化为

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行),则默认值不会更改

最后,我建议使用一个输出参数(甚至一个SELECT),而不是使用
RETURN
code

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


请参见

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

此外,在where子句中不需要使用
EXISTS()
,因为您有参数,只需进行简单的检查即可。如果
IF

IF @ExID IS NOT NULL -- you are checking the wrong variable here too
BEGIN
    RETURN @ExIDPK;
END;
ELSE
BEGIN
    RETURN 1234;
END;--This one
这是错误的,您根本不需要
,如果
,只需将其简化为

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行),则默认值不会更改

最后,我建议使用一个输出参数(甚至一个SELECT),而不是使用
RETURN
code

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


请参见

,因为这个问题是在理解返回值的机制的基础上提出的,所以我将把它作为一种更可取的机制来发布。通常,返回代码/返回值是为错误代码保留的,0表示成功,非0表示成功以外的其他内容(值得注意的例外是SQL Server代理运行状态)

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

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; 

因为这个问题是在理解返回值的机制的基础上提出的,所以我将把它作为一种更可取的机制来发布。通常,返回代码/返回值是为错误代码保留的,0表示成功,而非0表示成功(值得注意的例外是SQL Server代理运行状态

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

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; 

使用
EXISTS()的原因
WHERE
子句中?为什么不选择PK或使用输出参数?我的意思是,如果@ExID不为NULL,您知道它不为NULL,因为您给它一个值。这并不意味着您给它的值在dbo.ExIDs表上有匹配项……所以@ExIDPK可能为NULL,您也有一个
END;
中的分号是错误的,您根本不需要
,如果
,只需简单一点,并将变量的默认值设置为1234。为什么要使用
EXISTS()
WHERE
子句中?为什么不选择PK或使用输出参数?我的意思是,如果@ExID不为NULL,您知道它不为NULL,因为您给它一个值。这并不意味着您给它的值在dbo.ExIDs表上有匹配项……所以@ExIDPK可能为NULL,您也有一个
END;
中的分号是错误的,您根本不需要
,如果
,只需简化并将变量的默认值设置为1234即可。