how to set rowcount to zero in SQL - sql

anyone have an idea how to set rowcount to zero again in SQL.
I have used rowcount to fetch the number of records inserted in the insert statement. I have to use rowcount again to find the rows updated. So i am trying to reset the rowcount again to zero.
code will be look this :
INSERT INTO Table A ......
INSERT INTO statistics (id,inserted_records ) values (1,##rowcount)
---some operations--
Update Table A ....
Update statistics set updated_records=##rowcount where id=

select ##rowcount
only returns the row count from the most recent statement. It doesn't need to be reset.. Executing another statement will automatically reset it.
If for some bizarre reason, you want to make ##rowcount return 0, execute a query that will return 0 rows.
select 1 where 2=3
You can prove this like so.
declare #t table (i int)
declare #stats table(rc int)
insert #t values (1),(2),(3)
-- rowcount is 3
insert #stats values (##rowcount)
-- rowcount is 1
update #t set i=5 where i=4
select ##ROWCOUNT -- rowcount will be 0

#bibinmatthew ##ROWCOUNT automatically resets whenever you do another transaction.
What I would consider doing is
declare #rowsAffected int
insert into table A ...
select #rowsAffected = ##ROWCOUNT
insert into table statistics (id, inserted_records) values (iID, #rowsAffected)
declare #rowsAffected int
update table A ...
select #rowsAffected = ##ROWCOUNT
update table statistics set updated_records = #rowsAffected where id = iID
This way, you are not having to deal directly with the ##ROWCOUNT variable. I have created the #rowsAffected twice because I am assuming that you have the insert and the update scripts in different stored proc's

Information about rowcount are here:
http://technet.microsoft.com/en-us//library/ms187316.aspx
Statements such as USE, SET , DEALLOCATE CURSOR, CLOSE CURSOR,
BEGIN TRANSACTION or COMMIT TRANSACTION reset the ROWCOUNT value to 0
So maybe you can put the statements into a transaction, so they are better isolated against each other.
And you can always just send a request that does not update anything, like UPDATE mytable SET x=1 WHERE 0=1;

Related

value of the variable ##rowcount

having the following sql script:
declare #table table(id int)
insert into #table values (1),(2)
--print ##rowcount
if 3 < 2
print 'false'
--print ##rowcount
if I'm uncommenting the first print, it will print he value 2, but if I am uncommenting the last print, it will print 0. So the instruction IF is affecting the value of the variable ##ROWCOUNT? Or what is the scope of this variable?
I am using sql server 2014.
The Global variable ##ROWCOUNT will return the number of rows affected by the last statement. Run after the INSERT statement, it will return 2 (rows). Run after the IF statement, it will return the number of rows affected by the IF statement, which is zero.
This also means in the SQL below the 2 ##rowcount statements return 2 then 0 (zero) as the first ##rowcount statement affects zero rows
declare #table table(id int)
insert into #table values (1),(2)
print ##rowcount
print ##rowcount
Yes. ##ROWCOUNT refers to the previous statement and it is constantly being reassigned. This is why it is usually used for assignment to a variable:
declare #rowcnt int;
<whatever>
set #rowcnt = ##ROWCOUNT;
The documentation for ##ROWCOUNT gives examples of how it works in some situations, but doesn't list IF specifically.
However, with a bit of testing, it appears that an IF statement that was not executed resets it to 0. This makes sense if you think of IF as a statement that wraps the statement/block inside it:
if the condition was true, the IF statement affected however many rows the statement inside affected
if the condition was not true, and there is an ELSE block, it affected however many rows the statement inside that affected
if the condition was not true, and there is no ELSE it affects zero rows
Compare:
DECLARE #TEST TABLE(id INT)
INSERT INTO #TEST VALUES (1),(2),(3)
IF 1 = 2
SELECT * FROM #TEST
PRINT ##ROWCOUNT
-- 0, because block didn't run
IF 1 = 1
SELECT * FROM #TEST
PRINT ##ROWCOUNT
-- 3, i.e. number of rows in SELECT
IF 1 = 2
SELECT TOP 1 * FROM #TEST
ELSE
SELECT TOP 2 * FROM #TEST
PRINT ##ROWCOUNT
-- 2, i.e. number of rows in the SELECT executed in the ELSE clause

T-SQL TRIGGER return 1 more "Rows Affected" Than expected when INSERT data

I have a table with a secondary key. Before inserting, I want to check if this secondary key exists in another table as primary key.
To do this I've create a trigger in T-SQL on this table. Here it is:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[trg_tb_repair_order_before]
ON [dbo].[tb_repair_order]
INSTEAD OF INSERT
AS
BEGIN
DECLARE #or_code NVARCHAR(50)
DECLARE #or_designation NVARCHAR(300)
DECLARE #or_comment NVARCHAR(3000)
DECLARE #code_customer NVARCHAR(50)
DECLARE cur_tb_repair_order_before CURSOR FOR
SELECT or_code, or_designation, or_comment, code_customer
FROM inserted
OPEN cur_tb_repair_order_before
FETCH NEXT FROM cur_tb_repair_order_before INTO #or_code, #or_designation, #or_comment, #code_customer
WHILE ##FETCH_STATUS = 0
BEGIN
IF ((SELECT Count(*) FROM tb_customer WHERE code = #code_customer) > 0)
BEGIN
IF ((SELECT COUNT(*) FROM inserted) > 0)
BEGIN
INSERT INTO tb_repair_order (or_code, or_designation, or_comment, code_customer)
VALUES (#or_code, #or_designation, #or_comment, #code_customer)
END
END
FETCH NEXT FROM cur_tb_repair_order_before INTO #or_code, #or_designation, #or_comment, #code_customer
END
CLOSE cur_tb_repair_order_before
DEALLOCATE cur_tb_repair_order_before
END
Everything is good, this trigger works perfectly.
The problem is the number of rows inserted
Here is result for wrong secondary key
As we can see, SQL returns "1 rows affected" but nothing is inserted into the table ...
Here is result for good secondary key
And here SQL returns "2 rows affected".
If someone can explain how I can return the correct result because in my C# code the ExecuteNonQuery function returns not the expected result and it's bad practice to continue with this.
Thanks in advance

Multiple rows are getting inserted into a table (which is not desired) as part of a stored procedure

Update: This still remain a mystery. Checked the calling code and we did not find anything that would make the SP run in a loop.
For now we have split the SP into two which seems to have arrested the issue although not able to reason how that has helped out.
Database: MS SQL Server.
I have a SP which performs few operations - i.e inserts a row into 3 tables based on certain status as part of that SP being called.
It is getting called from our web application based on a user action.
We have cases, few times a day where the same row gets inserted multiple times (sometime more than 50+) with the same values in each row except that if you look at the datetime when the row was inserted there is a difference of few milliseconds. So it is unlikely that the user is initiating that action.
This SP is not running in a Transaction or with any locks however it is getting called probably concurrently multiple times as we have many concurrent users on the web application invoking this action.
My question is what is causing the same row to insert so many times? If concurrent execution of SP was an issue where we are updating same row then it is understood one may overwrite the other. However in this case each user calls in the SP with different parameters.
I have put the said operation in a Transaction to monitor the behavior however was looking to find out what exactly causes these kind of multiple inserts with same value just a few milliseconds apart?
USE [ABC]
GO
/****** Object: StoredProcedure [dbo].[AddProcessAdmittedDocUploadScrutinyWithLog] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[AddProcessAdmittedDocUploadScrutinyWithLog]
(
--Insert using bulk
#stdfrm_id int,
#course_id int,
#stdfrm_scrt_apprvby int,
#stdfrm_scrt_apprvcomment varchar(max),
#sRemainingDocs varchar(max),
#DTProcessAdmittedDocUploadScrutiny AS dbo.MyDTProcessAdmittedDocUploadScrutiny READONLY
)
AS
BEGIN
DECLARE #result char
SET #result='N'
--New
declare #AuditCount int=0;
select #AuditCount=count(scrtaudit_id) from tbl_ProcessAdmittedScrutinyAuditLog
where stdfrm_id=#stdfrm_id and stdfrm_scrt_apprvby=#stdfrm_scrt_apprvby
and stdfrm_scrt_apprvcomment=#stdfrm_scrt_apprvcomment and convert(date,stdfrm_scrt_apprvon,103)=convert(date,getdate(),103)
--Checked extra conditon to avoid repeatation
if(#AuditCount=0)
BEGIN
--Call Insert
BEGIN TRY
/*Remaining Documents----------*/
DECLARE #sdtdoc_id Table (n int primary key identity(1,1), id int)
if(#sRemainingDocs is not null)
begin
--INSERT INTO #sdtdoc_id (id) SELECT Name from splitstring(#sRemainingDocs)
INSERT INTO #sdtdoc_id (id) SELECT [Value] from dbo.FN_ListToTable(#sRemainingDocs,',')
end
Declare #isRemaining int=0;
SELECT #isRemaining=Count(*) FROM #sdtdoc_id
/*Calculate stdfrm_scrt_apprvstatus*/
Declare #stdfrm_scrt_apprvstatus char(1)='A';--Approved
Declare #TotalDescripancies int;
select #TotalDescripancies=count(doc_id) from #DTProcessAdmittedDocUploadScrutiny where doc_id_scrtyn='Y'
if(#isRemaining>0)
begin
set #stdfrm_scrt_apprvstatus='H';--Discrepancies Found
end
else if exists (select count(doc_id) from #DTProcessAdmittedDocUploadScrutiny where doc_id_scrtyn='Y')
begin
if(#TotalDescripancies>0)
begin
set #stdfrm_scrt_apprvstatus='H';--Discrepancies Found
end
end
/* Check if Discrepancies Found first time then assign to Checker o.w assign to direct college like grievance*/
if(#stdfrm_scrt_apprvstatus='H')
begin
declare #countAuditLog int=0;
select #countAuditLog=count(stdfrm_id) from tbl_ProcessAdmittedScrutinyAuditLog where stdfrm_id =#stdfrm_id
if (#countAuditLog=0)
begin
set #stdfrm_scrt_apprvstatus='G'--'E';--Discrepancies Found set Edit request assign to Checker
end
--else if (#countAuditLog=1)
-- begin
--set #stdfrm_scrt_apprvstatus='G';--Discrepancies Found set Grievance assign to college
-- end
end
/*----------------------*/
/*Update status in original table-----*/
Update tbl_ProcessAdmitted set stdfrm_scrt_apprvstatus=#stdfrm_scrt_apprvstatus
,stdfrm_scrt_apprvon=getdate(),stdfrm_scrt_apprvby=#stdfrm_scrt_apprvby
,stdfrm_scrt_apprvcomment=#stdfrm_scrt_apprvcomment
where stdfrm_id =#stdfrm_id
/*Add in Main Student Log-----------*/
/********* The row here gets inserted multiple times *******************/
INSERT into tbl_ProcessAdmittedScrutinyAuditLog
(stdfrm_id, stdfrm_scrt_apprvstatus, stdfrm_scrt_apprvon, stdfrm_scrt_apprvby, stdfrm_scrt_apprvcomment )
values
(#stdfrm_id, #stdfrm_scrt_apprvstatus, getdate(), #stdfrm_scrt_apprvby, #stdfrm_scrt_apprvcomment)
DECLARE #scrtaudit_id int =##identity
/*Completed -------------------------*/
DELETE FROM tbl_ProcessAdmittedDocUploadScrutiny WHERE stdfrm_id =#stdfrm_id
SET NOCOUNT ON;
/********* The row here gets inserted multiple times *******************/
INSERT tbl_ProcessAdmittedDocUploadScrutiny
(stdfrm_id, course_id, doc_id, doc_id_scrtyn, doc_id_scrtrmrk, doc_id_comment)
SELECT #stdfrm_id, #course_id, doc_id, doc_id_scrtyn, doc_id_scrtrmrk, doc_id_comment
FROM #DTProcessAdmittedDocUploadScrutiny;
/*Scrutiny Document Log -------------------------*/
/********* The row here gets inserted multiple times *******************/
INSERT tbl_ProcessAdmittedDocUploadScrutinyAuditLog
(scrtaudit_id,stdfrm_id, course_id, doc_id, doc_id_scrtyn, doc_id_scrtrmrk, doc_id_comment)
SELECT #scrtaudit_id,#stdfrm_id, #course_id, doc_id, doc_id_scrtyn, doc_id_scrtrmrk, doc_id_comment
FROM #DTProcessAdmittedDocUploadScrutiny;
/*Remaining Documents Insert into table*/
DELETE FROM tbl_ProcessAdmittedDocUploadScrutinyRemiaing WHERE stdfrm_id =#stdfrm_id
DECLARE #Id int,#doc_id int
WHILE (SELECT Count(*) FROM #sdtdoc_id) > 0
BEGIN
Select Top 1 #Id = n,#doc_id=id From #sdtdoc_id
--Do some processing here
insert into tbl_ProcessAdmittedDocUploadScrutinyRemiaing(stdfrm_id, doc_id )
values (#stdfrm_id,#doc_id)
insert into tbl_ProcessAdmittedDocUploadScrutinyRemiaingAuditLog
(scrtaudit_id, stdfrm_id, doc_id )
values (#scrtaudit_id,#stdfrm_id,#doc_id)
DELETE FROM #sdtdoc_id WHERE n = #Id
END --Begin end While
/*End Remaining Documents-----------*/
SET #result=#stdfrm_scrt_apprvstatus
END TRY
BEGIN CATCH
SET #result='N'
insert into tbl_ErrorSql( ErrorMessage, stdfrm_id)
values(coalesce(Error_Message(),ERROR_LINE()),#stdfrm_id)
END CATCH;
--End of Call Insert
END
SELECT #result
END

Is this sql update guaranteed to be atomic?

I have the following sql:
UPDATE Customer SET Count=1 WHERE ID=1 AND Count=0
SELECT ##ROWCOUNT
I need to know if this is guaranteed to be atomic.
If 2 users try this simultaneously, will only one succeed and get a return value of 1? Do I need to use a transaction or something else in order to guarantee this?
The goal is to get a unique 'Count' for the customer. Collisions in this system will almost never happen, so I am not concerned with the performance if a user has to query again (and again) to get a unique Count.
EDIT:
The goal is to not use a transaction if it is not needed. Also this logic is ran very infrequently (up to 100 per day), so I wanted to keep it as simple as possible.
It may depend on the sql server you are using. However for most, the answer is yes. I guess you are implementing a lock.
Using SQL SERVER (v 11.0.6020) that this is indeed an atomic operation as best as I can determine.
I wrote some test stored procedures to try to test this logic:
-- Attempt to update a Customer row with a new Count, returns
-- The current count (used as customer order number) and a bit
-- which determines success or failure. If #Success is 0, re-run
-- the query and try again.
CREATE PROCEDURE [dbo].[sp_TestUpdate]
(
#Count INT OUTPUT,
#Success BIT OUTPUT
)
AS
BEGIN
DECLARE #NextCount INT
SELECT #Count=Count FROM Customer WHERE ID=1
SET #NextCount = #Count + 1
UPDATE Customer SET Count=#NextCount WHERE ID=1 AND Count=#Count
SET #Success=##ROWCOUNT
END
And:
-- Loop (many times) trying to get a number and insert in into another
-- table. Execute this loop concurrently in several different windows
-- using SMSS.
CREATE PROCEDURE [dbo].[sp_TestLoop]
AS
BEGIN
DECLARE #Iterations INT
DECLARE #Counter INT
DECLARE #Count INT
DECLARE #Success BIT
SET #Iterations = 40000
SET #Counter = 0
WHILE (#Counter < #Iterations)
BEGIN
SET #Counter = #Counter + 1
EXEC sp_TestUpdate #Count = #Count OUTPUT , #Success = #Success OUTPUT
IF (#Success=1)
BEGIN
INSERT INTO TestImage (ImageNumber) VALUES (#Count)
END
END
END
This code ran, creating unique sequential ImageNumber values in the TestImage table. This proves that the above SQL update call is indeed atomic. Neither function guaranteed the updates were done, but they did guarantee that no duplicates were created, and no numbers were skipped.

About lock behavior when update row in sql server

Now, I'm trying to increment number sequential in SQL Server with the number provided from users.
I have a problem when multiple user insert a row same time with same number.
I try to update the number that user provided to a temporary table, and I expect when I update the same table with same condition, SQL Server will lock any modified to this row until the current update finished, but it not.
Here is the update statement I used:
UPDATE GlobalParam
SET ValueString = (CAST(ValueString as bigint) + 1)
WHERE Id = 'xxxx'
Could you tell me any way to force the other update command wait until the current command finished ?
This is entire my command :
DECLARE #Result bigint;
UPDATE GlobalParam SET ValueString = (SELECT MAX(Code) FROM Item)
DECLARE #SelectTopStm nvarchar(MAX);
DECLARE #ExistRow int
SET #SelectTopStm = 'SELECT #ExistRow = 1 FROM (SELECT TOP 1 Code FROM Item WHERE Code = '999') temp'
EXEC sp_executesql #SelectTopStm, N'#ExistRow int output', #ExistRow output
IF (#ExistRow is not null)
BEGIN
DECLARE #MaxValue bigint
DECLARE #ReturnUpdateTbl table (ValueString nvarchar(max));
UPDATE GlobalParam SET ValueString = (CAST(ValueString as bigint) + 1)
OUTPUT inserted.ValueString INTO #ReturnUpdateTbl
WHERE [Id] = '333A8E1F-16DD-E411-8280-D4BED9D726B3'
SELECT TOP 1 #MaxValue = CAST(ValueString as bigint) FROM #ReturnUpdateTbl
SET #Result = #MaxValue
END
ELSE
BEGIN
SET #Output = 999
END
END
I write the codes above as a stored procedure.
Here is the real code when I insert one Item:
DECLARE #IncrementResult BIGINT
EXEC IncrementNumberUnique
, (some parameters)..
,#Result = #IncrementResult OUTPUT
INSERT INTO ITEM (Id, Code) VALUES ('xxxx', #IncrementResult)
I create 3 threads and make it run at the same time.
The return result :
Id Code
1 999
2 1000
3 1000
Thanks
If I understood your requirements, try ROWLOCK hint to tell the optimizer to start with locking the rows one by one as the update needs them.
UPDATE GlobalParam WITH(ROWLOCK)
SET ValueString = (CAST(ValueString as bigint) + 1)
WHERE Id = 'xxxx'
By default SQL Server does READ Committed locking which releases READ locks once the read operation is committed. Once the Update statement below is complete, all read locks are released from the table Item.
UPDATE GlobalParam SET ValueString = (SELECT MAX(Code) FROM Item)
Since your INSERT into Item is outside the scope of your procedure. you can run the thread in SERIALIZABLE isolation level. Something like this.
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
DECLARE #IncrementResult BIGINT
EXEC IncrementNumberUnique
, (some parameters)..
,#Result = #IncrementResult OUTPUT
INSERT INTO ITEM (Id, Code) VALUES ('xxxx', #IncrementResult)
Changing the isolation level to SERIALIZABLE will increase blocking and contention of resources on item table.
To know more about isolation level, refer this
you should look into identity columns and remove such manual computation of incremental columns if possible.