##ROWCOUNT check not detecting zero row count - sql

I have a SQL Server Stored Procedure (using SQL Server 2008 R2) where it performs several different table updates. When rows have been updated I want to record information in an Audit table.
Here is my pseudo code:
UPDATE tblName SET flag = 'Y' WHERE flag = 'N'
IF ##ROWCOUNT > 0
BEGIN
INSERT INTO auditTable...etc
END
Unfortunately, even when zero rows are updated it still records the action in the audit table.
Note: There are no related triggers on the table being updated.
Any ideas why this could be happening?

Any statement that is executed in T-SQL will set the ##rowcount, even the if statement, so the general rule is to capture the value in the statement following the statement you're interested in.
So after
update table set ....
you want
Select #mycount = ##Rowcount
Then you use this value to do your flow control or messages.
As the docs state, even a simple variable assignment will set the ##rowcount to 1.
This is why it's important in this case that if you want people to diagnose the problem then you need to provide the actual code, not pseudo code.

Related

Updating or deleting a sql table for non existent record

How does SQL behave and what does it return when I try updating or deleting a on existent record in the table. I checked running an update on a non existent record and the query basically runs, doesn't do anything and returns saying a no records were affected. However I wanted to understand how it works internally and what would the result variable hold after such queries.
It depends on the database but usually you can get the affected rows after update or insert.
If nothing is updated you will get 0 for the rowcount.
Pl SQL example:
declare
i number;
begin
update MyTable set status = 'someStatus' where name = 'someName';
i := sql%rowcount;
end;
T-SQL example:
UPDATE Table Set Column = 0 WHERE Column IS NULL
SELECT #RowCount = ##ROWCOUNT
How it works internaly depends on the database vendor.

getting number of records updated or inserted in sql server stored procedure

I have an SP that inserts some records and updates others and deletes some. What I want is to return the count values of what was inserted and what was updated and what was deleted. I thought I could use ##ROWCOUNT but that is always giving me a 1.
After my INSERT I run:
PRINT ##ROWCOUNT
But my message console shows what really happened and this number:
(36 row(s) affected)
1
So I can see that 36 records were actually updated but ##ROWCOUNT returned a 1.
I am trying to do the same thing after the UPDATE and DELETE parts of the SP runs with the same result.
##ROWCOUNT will show the number of rows affected by the most recent statement - if you have any statements between the INSERT and the PRINT then it will give you the wrong number.
Can you show us a little more code so we can see the order of execution?
Depending on how #ninesided's answer works for you, you could also use the output clause on each update/insert/delete and get the counts from there.
Example:
declare #count table
(
id int
)
update mytable
set oldVal = newVal
output inserted.field1 into #count
select count(*) from #count
You could reuse the count table throughout, and set variables as needed to hold the values.

Need example of Conditional update stored proc in SQL server

I am just at starting levels in DB usage and have 2 basic questions
I have a generic UPDATE stored proc which updates all columns of a table.
But i need to make it conditional wherein it does not SET when the parameter is NULL.
Usage: I want to use this as a single SP to UPDATE any subset of columns, the caller from C# will fill in corresponding parameter values and leave other parameters NULL.
2
In case of , "UPDATE selected records" do i need to use locking inside stored proc ?
Why ? Isn't the operation in itself locked and transactional ?
I find the same question come up when i need to UPDATE selected(condition) records and then Return updated records.
UPDATE table
SET a = case when #a is null then a else #a end
WHERE id = #id
OR
EXEC 'update table set ' + #update + ' where id = ' + #id
OR
Conditionally update a column at a time
First option to me would usually be preferrable as it is usually efficient enough and you do not need to worry about string escaping
If I have understood the question properly, Why can't you build a query on the fly from sql server SP, and use sp_sqlexecute. So when you build query you can ensure only columns that have value has got updated.
Does this answer your question?

Database transaction only partially committing

I've got a T-SQL stored procedure running on a Sybase ASE database server that is sometimes failing to commit all of its operations, even though it completes without exception. Here's a rough example of what it does.
BEGIN TRANSACTION
UPDATE TABLE1
SET FIELD1 = #NEW_VALUE1
WHERE KEY1 = #KEY_VALUE1
IF ##error <> 0 OR ##rowcount <> 1 BEGIN
ROLLBACK
RETURN 1
END
UPDATE TABLE2
SET FIELD2 = #NEW_VALUE2
WHERE KEY2 = #KEY_VALUE2
IF ##error <> 0 OR ##rowcount <> 1 BEGIN
ROLLBACK
RETURN 2
END
INSERT TABLE2 (FIELD2, FIELD3)
VALUES (#NEW_VALUE3a, #NEW_VALUE3b)
IF ##error <> 0 OR ##rowcount <> 1 BEGIN
ROLLBACK
RETURN 3
END
COMMIT TRANSACTION
RETURN 0
The procedure is called at least hundreds of times a day. In a small percentage of those cases (probably < 3%), only the INSERT statement commits. The proc completes and returns 0, but the two UPDATEs don't take. Originally we thought it might be that the WHERE clauses on the UPDATEs weren't matching anything, so we added the IF ##rowcount logic. But even with those checks in there, the INSERT is still happening and the procedure is still completing and returning 0.
I'm looking for ideas about what might cause this type of problem. Is there anything about the way SQL transactions work, or the way Sybase works specifically, that could be causing the COMMIT not to commit everything? Is there something about my IF blocks that could allow the UPDATE to not match anything but the procedure to continue? Any other ideas?
is is possible that they are updating, but something is changing the values back? try adding a update trigger on those tables and within that trigger insert into a log table. for rows that appear to have not been updated look in the log, is there a row or not?
Not knowing how you set the values for your variables, it occurs to me that if the value of #NEW_VALUE1 is the same as the previous value in FIELD1 , the update would succeed and yet appear to have not changed anything making you think the transaction had not happened.
You also could have a trigger that is affecting the update.

How can I do a BEFORE UPDATED trigger with sql server?

I'm using Sqlserver express and I can't do before updated trigger. There's a other way to do that?
MSSQL does not support BEFORE triggers. The closest you have is INSTEAD OF triggers but their behavior is different to that of BEFORE triggers in MySQL.
You can learn more about them here, and note that INSTEAD OF triggers "Specifies that the trigger is executed instead of the triggering SQL statement, thus overriding the actions of the triggering statements." Thus, actions on the update may not take place if the trigger is not properly written/handled. Cascading actions are also affected.
You may instead want to use a different approach to what you are trying to achieve.
It is true that there aren't "before triggers" in MSSQL. However, you could still track the changes that were made on the table, by using the "inserted" and "deleted" tables together. When an update causes the trigger to fire, the "inserted" table stores the new values and the "deleted" table stores the old values. Once having this info, you could relatively easy simulate the "before trigger" behaviour.
Can't be sure if this applied to SQL Server Express, but you can still access the "before" data even if your trigger is happening AFTER the update. You need to read the data from either the deleted or inserted table that is created on the fly when the table is changed. This is essentially what #Stamen says, but I still needed to explore further to understand that (helpful!) answer.
The deleted table stores copies of the affected rows during DELETE and
UPDATE statements. During the execution of a DELETE or UPDATE
statement, rows are deleted from the trigger table and transferred to
the deleted table...
The inserted table stores copies of the affected rows during INSERT
and UPDATE statements. During an insert or update transaction, new
rows are added to both the inserted table and the trigger table...
https://msdn.microsoft.com/en-us/library/ms191300.aspx
So you can create your trigger to read data from one of those tables, e.g.
CREATE TRIGGER <TriggerName> ON <TableName>
AFTER UPDATE
AS
BEGIN
INSERT INTO <HistoryTable> ( <columns...>, DateChanged )
SELECT <columns...>, getdate()
FROM deleted;
END;
My example is based on the one here:
http://www.seemoredata.com/en/showthread.php?134-Example-of-BEFORE-UPDATE-trigger-in-Sql-Server-good-for-Type-2-dimension-table-updates
sql-server triggers
T-SQL supports only AFTER and INSTEAD OF triggers, it does not feature a BEFORE trigger, as found in some other RDBMSs.
I believe you will want to use an INSTEAD OF trigger.
All "normal" triggers in SQL Server are "AFTER ..." triggers. There are no "BEFORE ..." triggers.
To do something before an update, check out INSTEAD OF UPDATE Triggers.
To do a BEFORE UPDATE in SQL Server I use a trick. I do a false update of the record (UPDATE Table SET Field = Field), in such way I get the previous image of the record.
Remember that when you use an instead trigger, it will not commit the insert unless you specifically tell it to in the trigger. Instead of really means do this instead of what you normally do, so none of the normal insert actions would happen.
Full example:
CREATE TRIGGER [dbo].[trig_020_Original_010_010_Gamechanger]
ON [dbo].[T_Original]
AFTER UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #Old_Gamechanger int;
DECLARE #New_Gamechanger int;
-- Insert statements for trigger here
SELECT #Old_Gamechanger = Gamechanger from DELETED;
SELECT #New_Gamechanger = Gamechanger from INSERTED;
IF #Old_Gamechanger != #New_Gamechanger
BEGIN
INSERT INTO [dbo].T_History(ChangeDate, Reason, Callcenter_ID, Old_Gamechanger, New_Gamechanger)
SELECT GETDATE(), 'Time for a change', Callcenter_ID, #Old_Gamechanger, #New_Gamechanger
FROM deleted
;
END
END
The updated or deleted values are stored in DELETED. we can get it by the below method in trigger
Full example,
CREATE TRIGGER PRODUCT_UPDATE ON PRODUCTS
FOR UPDATE
AS
BEGIN
DECLARE #PRODUCT_NAME_OLD VARCHAR(100)
DECLARE #PRODUCT_NAME_NEW VARCHAR(100)
SELECT #PRODUCT_NAME_OLD = product_name from DELETED
SELECT #PRODUCT_NAME_NEW = product_name from INSERTED
END