我有以下存储过程。
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
感谢
答案 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
202
10
201 - 由于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)(强调我的大胆)
将最后一个标识值插入返回到同一范围内的标识列。范围是一个模块:存储过程,触发器,函数或批处理。因此,如果两个语句在同一存储过程,函数或批处理中,则它们在同一范围内。
您正在进行更新,而不是插入,因此未进行设置。