为什么@@ RowCount显示1行受影响但SCOPE_IDENTITY()返回NULL?

时间:2014-12-18 01:43:45

标签: sql-server-2008 tsql

我有以下存储过程。

alter proc uspUpdtStudent
@pStudID int, 
@pTitle char(10),
@pFName varchar(50), 
@pLName varchar(50), 
@pDOB date,
@pGender char(1),
@pIsPriorStud bit, 
@pCitizen varchar(50), 
@pResidency varchar(50), 
@pPic varbinary(max),
--@pOldContact as dbo.Contact readonly, 
@pNewContact as dbo.Contact readonly, 
@pProgTrack tinyint,
@pProgID int,
@pid int output -- why not EnrID? 
as
begin 
SET NOCOUNT ON;

    declare @tblNew as table (rw_id int identity(1,1), addL1 varchar(200), sub varchar(100), town varchar(100), post int)

select @pTitle, @pFName, @pLName, @pDOB, @pGender, @pIsPriorStud, @pCitizen, @pResidency, @pPic, @pStudID

    update dbo.Students 
    set 
    Title=@pTitle, 
    FName=@pFName, 
    LName=@pLName, 
    DOB=@pDOB, 
    Gender=@pGender, 
    IsPriorStud=@pIsPriorStud, 
    Citizenship=@pCitizen, 
    Residency=@pResidency, 
    StudImg=@pPic, 
    DateOfRago=GETDATE() 
    where StudID =@pStudID

    select @pStudID as 'Passed Student ID' 

    declare @rowcount int

            set @pid = SCOPE_IDENTITY()
            --select @pid

            set @rowcount = @@ROWCOUNT

            select @rowcount as 'Effected Row count'    
    if @rowcount > 0
    begin 

        SELECT   @pid as 'Student table row ID'


    end
    else
    begin
        set @pid = -1
        --rollback tran
        return 302
    end


end
go

然后我将这些值传递给存储过程

USE [SMSV1]
GO

declare @p13 int
set @p13=-1
declare @p14 dbo.Contact
insert into @p14 values(N'fyyyfyf',N'woeoeoo',N'kokokok',N'123456')

exec uspUpdtStudent @pStudID=100000007,@pTitle=N'Mr.',@pFName=N'George',@pLName=N'kadafi',@pDOB='1940-12-12 00:00:00',@pGender=N'M',@pIsPriorStud=0,@pCitizen=N'LIBIYA',@pResidency=N'LIBIYA',@pPic=null,@pProgID=15,@pProgTrack=2,@pid=@p13 output,@pNewContact=@p14

有趣的是,它在学生表中添加了一行,但当我尝试从SCOPE_IDENTITY()访问行ID时,它显示为NULL。 IF条件执行因为@@ROWCOUNT大于零也正如您在代码中看到的那样,我甚至将id值保存在变量@pid中。我已附上this video on youtube,因此了解情况可能会有所帮助。

这是我的学生表

USE [SMSV1]
GO

/****** Object:  Table [dbo].[Students]    Script Date: 12/18/2014 07:39:08 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[Students](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [StudID] [int] NULL,
    [Title] [char](10) NULL,
    [FName] [varchar](50) NULL,
    [LName] [varchar](50) NULL,
    [DOB] [date] NULL,
    [Gender] [char](1) NULL,
    [IsPriorStud] [bit] NULL,
    [Citizenship] [varchar](50) NULL,
    [Residency] [varchar](50) NULL,
    [StudImg] [varbinary](max) NULL,
    [DateOfRago] [datetime] NULL,
    [Updt] [datetime] NOT NULL,
    [IsActive] [bit] NULL,
 CONSTRAINT [PK_Students] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE [dbo].[Students] ADD  CONSTRAINT [DF_Students_Updt]  DEFAULT (getdate()) FOR [Updt]
GO

感谢

2 个答案:

答案 0 :(得分:4)

每个语句都会重置

@@ROWCOUNT。请尝试以下方法查看:

DECLARE @Test INT;
SELECT 10 UNION ALL SELECT 20;
SELECT @@ROWCOUNT;

SELECT 10 UNION ALL SELECT 20;
SET @Test = 1;
SELECT @@ROWCOUNT;

返回:

  

10
  20

     

2

     

10
  20

     

1 - 由于SET命令介于后两个SELECT

之间,因此该值为1而不是2

如果您希望SET @RowCount = @@ROWCOUNT;准确无误,则必须是UPDATE之后的下一个语句。您目前所拥有的位置(即在SET命令之后)@rowcount无论UPDATE发生什么,都将始终为1。

此外,没有INSERT,因此SCOPE_IDENTITY()必须返回NULL。为什么你还需要动态获取ID呢?是不是通过@pStudID传递到了proc?如果由于某种原因[StudID]表中的[Students]字段不是IDENTITY字段,您仍然可以通过OUTPUT子句获取该字段:

UPDATE dbo.Students 
SET 
    Title=@pTitle, 
    FName=@pFName, 
    LName=@pLName, 
    DOB=@pDOB, 
    Gender=@pGender, 
    IsPriorStud=@pIsPriorStud, 
    Citizenship=@pCitizen, 
    Residency=@pResidency, 
    StudImg=@pPic, 
    DateOfRago=GETDATE() 
OUTPUT INSERTED.ID -- this is the IDENTITY field as per the CREATE TABLE statement
WHERE StudID = @pStudID;

以这种方式使用OUTPUT子句将导致仅在更新行时设置1行1列结果。如果没有匹配的行,则没有结果集。如果您想要更清楚地指示没有更新行而不是仅仅没有结果集,如上所述,请在更新后放置SET @RowCount = @@ROWCOUNT;,然后您可以测试IF (@RowCount = 0)...

如果您需要ID变量中的@pid字段,因为它是OUTPUT参数,那么您需要将UPDATE...OUTPUT的结果集捕获到临时表或表变量中:

DECLARE @UpdatedID TABLE (ID INT);

UPDATE dbo.Students 
SET 
    Title=@pTitle, 
    FName=@pFName, 
    LName=@pLName, 
    DOB=@pDOB, 
    Gender=@pGender, 
    IsPriorStud=@pIsPriorStud, 
    Citizenship=@pCitizen, 
    Residency=@pResidency, 
    StudImg=@pPic, 
    DateOfRago=GETDATE() 
OUTPUT INSERTED.ID -- this is the IDENTITY field as per the CREATE TABLE statement
INTO   @UpdatedID (ID)
WHERE StudID = @pStudID;

SELECT @pid = ID
FROM   @UpdatedID;

IF (@pid IS NULL)
BEGIN
  SET @pid = -1;
  RETURN 302;
END;

答案 1 :(得分:1)

来自SCOPE_IDENTITY (Transact-SQL)(强调我的大胆)

将最后一个标识值插入返回到同一范围内的标识列。范围是一个模块:存储过程,触发器,函数或批处理。因此,如果两个语句在同一存储过程,函数或批处理中,则它们在同一范围内。

您正在进行更新,而不是插入,因此未进行设置。