Stored Procedure with update statement not functioning - sql-server

I have created a very simple stored procedure and verified that the query that needs to be executed is a correct/running query. Yet, once stored in the SP, it does not do anything apart from returning '0':
USE [test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[GenerateVolume]
AS
BEGIN
SET NOCOUNT ON;
UPDATE test.dbo.[c500 CP_Simulation]
set GeneratedVolume = AvgFillRatePerDayPerCP +[dbo].[fn_InvsNorm](RAND(convert(varbinary, newid()))) * StDevFillRatePerDayPerCP
where test.dbo.[c500 CP_Simulation].OrgVPnr = test.dbo.[c500 CP_Simulation].OrgVPnr
END
No errors are given... Please give me a tip :)

When you use the
SET NOCOUNT ON
It will suppress the "xx rows affected" message.
If your query works fine, your rows are getting updated.
Since you have told sql server not to count how many rows were updated, you will not be told how many rows got updated.
Hope that clears some doubt.

Related

SQL Server stored procedure - update one table and insert into another table

I've got a stored procedure that is coded similarly to the following:
USE [database]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROC [dbo].[procedure_name]
#record_id int
, #record_value VARCHAR(MAX)
AS
BEGIN
UPDATE dbo.table_1
SET table_1_record_value = #record_value
WHERE table_1_record_int = #record_int
END
BEGIN
INSERT INTO table_2 COLUMNS (table_2_record_id, table_2_record_value) VALUES (#record_id, #record_value)
END
And I'm getting a syntax error. I've never had to write a stored procedure for an application that would accomplish both an UPDATE and an INSERT statement together.
The answer was provided by bbaird in the comments. Removing the BEGIN/END keywords fixed the problem. Thank you!
bbaird's full comment below:
If the procedure isn't created yet, you will need to do CREATE PROCEDURE. 2. The update and insert statements are independent, no need to put them in their own BEGIN...END block unless there is a conditional. 3. COLUMNS in the insert statement might also be throwing things off - it is not necessary so remove it.
The answers of Jake and bbard are correct.
Below the code of your stored procedure:
USE [database]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE OR ALTER PROC [dbo].[procedure_name]
#record_id int
, #record_value VARCHAR(MAX)
AS
BEGIN
UPDATE dbo.table_1
SET table_1_record_value = #record_value
WHERE table_1_record_int = #record_int
INSERT INTO table_2 COLUMNS (table_2_record_id, table_2_record_value)
VALUES (#record_id, #record_value)
END
For documentation of BEGIN and END look here

Is "SET NOCOUNT ON" a good choice for a placeholder stored procedure body?

These answers (1, 2), using code from this article, recommend using the statement SET NOCOUNT ON as a temporary placeholder/dummy body for a stored procedure whose body will be overwritten shortly.
Neither those answers nor that article specify why SET NOCOUNT ON was chosen as the value for the temporary stored procedure body.
My question: Why is SET NOCOUNT ON a good choice for a temporary stored procedure body which will (if all goes well) be overwritten in a subsequent operation? Is there a better alternative?
Some criteria that come to mind for what might constitute a good temporary / placeholder stored procedure body:
Fails in an obvious way at runtime if for some reason the subsequent ALTER of the stored procedure doesn't happen as planned;
Is easy to understand by future developers maintaining the stored procedure;
Doesn't add any significant overhead.
To better meet the "criteria" from my question, I've landed on replacing SET NOCOUNT ON with a RAISERROR statement.
My code to ensure a stored procedure exists before running an ALTER PROCEDURE on it ends up looking like:
-- Create the sproc with a temporary body if it doesn't exist yet.
-- We'll set the real body in the ALTER PROCEDURE statement below.
IF NOT EXISTS (
SELECT * FROM sys.objects
WHERE name = 'MyStoredProcedureNameHere'
AND type = 'P'
) BEGIN
EXEC ('CREATE PROCEDURE MyStoredProcedureNameHere AS
RAISERROR (''The ALTER PROCEDURE to set the body for MyStoredProcedureNameHere did not run as it should have!'', 16, 1);');
END
GO
ALTER PROCEDURE MyStoredProcedureNameHere AS ...
So, if the ALTER PROCEDURE somehow fails to run, then if my stored procedure gets executed, it'll raise an error instead of silently doing nothing (as would be the case with a body consisting only of SET NOCOUNT ON).
Credit for this approach: http://www.codeofhonor.com/blog/a-better-way-to-update-sql-stored-procedures
This is probably because including SET NOCOUNT ON; is considered good practice. It is included in the template SP, generated by SSMS. From the MSDN article on NOCOUNT:
NOCOUNT ON prevents the sending of DONE_IN_PROC messages to the client for
each statement in a stored procedure. For stored procedures that
contain several statements that do not return much actual data, or for
procedures that contain Transact-SQL loops, setting SET NOCOUNT to ON
can provide a significant performance boost, because network traffic
is greatly reduced.
The idea is NOCOUNT is first used a placeholder. Later you add to, rather than replace, this statement.

SET NOCOUNT ON Still returns a "nn row(s) affected" message

I have a simple stored procedure that simply selects data from a couple of tables and has only 1 input. The way I have set up my stored procedure is as follows:
CREATE PROCEDURE dbo.Proc_Name
(
#input
)
AS
BEGIN
SET NOCOUNT ON
BEGIN TRY
(
SELECT statements go here
)
END TRY
BEGIN CATCH
END CATCH
END
Despite of putting the SET NOCOUNT ON, I still get "nn row(s) affected" message when I call the stored procedure.
I tried changing the location of the SET NOCOUNT ON, but that does not help either.
The other thing that I noticed was that my stored procedure returns a:
Warning: Null value is eliminated by an aggregate or other SET operation.
message.
Is this warning throwing off the SET NOCOUNT ON hint?
The syntax for your proc is incorrect. It should be:
CREATE PROCEDURE dbo.Proc_Name
#input
AS
BEGIN...
The parentheses are invalid around the parameters and you need the keyword AS. I would correct this and make sure that your proc is actually compiling.
The warning means that you are aggregating a nullable column and it will return some value even if there are nulls.
My bad folks. The proc name resembles too closely to another proc name. Turns out I was calling the wrong procedure and it was working fine. I changed my call and it works fine now. Thanks for your time.

How can I make a stored procedure commit immediately?

EDIT This questions is no longer valid as the issue was something else. Please see my explanation below in my answer.
I'm not sure of the etiquette so i'l leave this question in its' current state
I have a stored procedure that writes some data to a table.
I'm using Microsoft Practices Enterprise library for making my stored procedure call.
I invoke the stored procedure using a call to ExecuteNonQuery.
After ExecuteNonQuery returns i invoke a 3rd party library. It calls back to me on a separate thread in about 100 ms.
I then invoke another stored procedure to pull the data I had just written.
In about 99% of cases the data is returned. Once in a while it returns no rows( ie it can't find the data). If I put a conditional break point to detect this condition in the debugger and manually rerun the stored procedure it always returns my data.
This makes me believe the writing stored procedure is working just not committing when its called.
I'm fairly novice when it comes to sql, so its entirely possible that I'm doing something wrong. I would have thought that the writing stored procedure would block until its contents were committed to the db.
Writing Stored Procedure
ALTER PROCEDURE [dbo].[spWrite]
#guid varchar(50),
#data varchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- see if this guid has already been added to the table
DECLARE #foundGuid varchar(50);
SELECT #foundGuid = [guid] from [dbo].[Details] where [guid] = #guid;
IF #foundGuid IS NULL
-- first time we've seen this guid
INSERT INTO [dbo].[Details] ( [guid], data ) VALUES (#guid, #data)
ELSE
-- updaeting or verifying order
UPDATE [dbo].[Details] SET data =#data WHERE [guid] = #guid
END
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Reading Stored Procedure
ALTER PROCEDURE [dbo].[spRead]
#guid varchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT * from [dbo].[Details] where [guid] = #guid;
END
To actually block other transactions and manually commit,
maybe adding
BEGIN TRANSACTION
--place your
--transactions you wish to do here
--if everything was okay
COMMIT TRANSACTION
--or
--ROLLBACK TRANSACTION if something went wrong
could help you?
I’m not familiar with the data access tools you mention, but from your description I would guess that either the process does not wait for the stored procedure to complete execution before proceeding to the next steps, or ye olde “something else” is messing with the data in between your write and read calls.
One way to tell what’s going on is to use SQL Profiler. Fire it up, monitor all possible query execution events on the database (including stored procedure and stored procedures line start/stop events), watch the Text and Started/Ended columns, correlate this with the times you are seeing while tracing the application, and that should help you figure out what’s going on there. (SQL Profiler can be complex to use, but there are many sources on the web that explain it, and it is well worth learning how to use it.)
I'll leave my answer below as there are comments on it...
Ok, I feel shame I had simplified my question too much. What was actually happening is two things:
1) the inserting procedure is actually running on a separate machine( distributed system).
2) the inserting procedure actually inserts data into two tables without a transaction.
This means the query can run at the same time and find the tables in a state where one has been written to and the second table hasn't' yet had its write committed.
A simple transaction fixes this as the reading query can handle either case of no write or full write but couldn't handle the case of one table written to and the other having a pending commit.
Well it turns out that when I created the stored procedure the MSSQLadmin tool added a line to it by default:
SET NOCOUNT ON;
If I turn that to:
SET NOCOUNT OFF;
then my procedure actually commits to the database properly. Strange that this default would actually end up causing problems.
Easy way using try-catch, like it if useful
BEGIN TRAN
BEGIN try
INSERT INTO meals
(
...
)
Values(...)
COMMIT TRAN
END try
BEGIN catch
ROLLBACK TRAN
SET #resp = (convert(varchar,ERROR_LINE()), ERROR_MESSAGE() )
END catch

SET NOCOUNT ON brings back messages in SQL Server Management Studio

I have the following stored procedure:
ALTER PROCEDURE [dbo].[spTitle_GetTitleById]
(
#TitleId INT
)
AS
BEGIN
SET NOCOUNT ON;
SELECT
Id,
Name,
Active
FROM
Title
WHERE
Id = #TitleId
END
I was told to use SET NOCOUNT ON; if I don't want messages to be returned. I ran this stored procedure through SQL Server Management Studio 2008 and I got the following message:
(1 row(s) affected)
This is still a message. One of our DBAs said that this will be the case, but when it is run through an application it will not return any messages. Is there a way that I can test to see if messages were returned or not when I use SET NOCOUNT ON; I don't want to assume, I want to know.
I right clicked the stored procedure and selected Execute Stored Procedure... I then set it to OFF, and I got:
(1 row(s) affected)
(1 row(s) affected)
So setting it to ON or OFF it still brought back messages in the Messages tab in the results panel.
Just another question, when will it be wise (in what scenarios) to use SET NOCOUNT OFF;?
SET NOCOUNT ON is reset when the procedure exits and it goes up the call stack. When you execute the procedure from SSMS it generates a script like the following.
DECLARE #return_value int
EXEC #return_value = [dbo].[spTitle_GetTitleById]
#TitleId = 1
SELECT 'Return Value' = #return_value /*Message comes from here*/
If youi wanted to avoid that for some reason you would need to SET NOCOUNT ON in the outer batch. See SET NOCOUNT ON usage for some discussion about the merits of having this ON or OFF
Just another question, when will it be wise (in what scenarios) to use SET NOCOUNT OFF?
See What are the advantages and disadvantages of turning NOCOUNT off in SQL Server queries? For the benefits turning SET NOCOUNT ON
As for why you would want to turn this off (so that rowcounts are returned) - you need this off whenever you want to be able to tell how many rows were affected in situations where there is no resultset, or you wish to be able to get a rowcount without first reading through the entire resultset.
For example in .Net the DataAdapter class uses rowcounts and so setting NOCOUNT ON causes issues when editing or deleting data (source).
That is not correct, script out the proc an make sure it is not OFF instead o ON, if it is ON it should not return (1 row(s) affected) messages
Also how are you executing the proc
is is just this
exec spTitle_GetTitleById 1

Resources