SET NOCOUNT ON and Cursors - sql

I have a stored proc that calls several store procs, each of which insert dummy data into a single table each. It works fine except that for each loop in the cursor a single row of results is dispayed - just showing ClubcardId = 2, ClubcardId = 3 etc.
I have used the SET NOCOUNT ON but this doesn't seem to help. I'm looking for this stored proc to create several million rows so, SQL printing the result for each row will be an issue.
Could anyone please advise how to prevent the output from being displayed. I have copied the parent stored proc below. I can be sure that the display is not coming from the child stored proc - lap_CreateClubcardTransaction.
If I change:
DECLARE Clubcard_Cursor CURSOR FAST_FORWARD FOR
SELECT ClubcardId FROM Clubcard
...to:
DECLARE Clubcard_Cursor CURSOR FAST_FORWARD FOR
SELECT ClubcardId as 'TEST' FROM Clubcard
...then the I get the value 'TEST' displayed for each row of the cursor.
Here's the parent stored proc:
ALTER PROCEDURE [dbo].[lap_CreateDummyData]
AS
SET NOCOUNT ON
DECLARE #NumberOfCustomers bigint
DECLARE #NumberOfTransactions bigint
SET #NumberOfCustomers = 50000
SET #NumberOfTransactions = 10
EXEC lap_CreateCustomer #NumberOfCustomers = #NumberOfCustomers;
EXEC lap_CreateCustomerPreference #NumberOfCustomers = #NumberOfCustomers;
EXEC lap_CreateClubCard #NumberOfCustomers = #NumberOfCustomers;
EXEC lap_CreateClubCardOffer #NumberOfCustomers = #NumberOfCustomers;
--get static data details to use when creating transaction records
DECLARE #TransactionType tinyint
DECLARE #TransactionReasonID tinyint
DECLARE #TescoStoreID int
DECLARE #PartnerID bigint
DECLARE #PartnerOutletID bigint
DECLARE #ClubcardID bigint
SET #TransactionType = (SELECT TOP 1 TransactionType FROM TransactionType)
SET #TransactionReasonID = (SELECT TOP 1 TransactionReasonID FROM TransactionReason)
SET #TescoStoreID = (SELECT TOP 1 TescoStoreId FROM TescoStore)
SET #PartnerID = (SELECT TOP 1 PartnerID FROM PartnerOutlet)
SET #PartnerOutletID = (SELECT TOP 1 PartnerOutletID FROM PartnerOutlet)
DECLARE Clubcard_Cursor CURSOR FAST_FORWARD FOR
SELECT ClubcardId FROM Clubcard
OPEN Clubcard_Cursor
FETCH NEXT FROM Clubcard_Cursor
INTO #ClubcardID SET NOCOUNT ON
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC lap_CreateClubcardTransaction #NumberOfTransactions = #NumberOfTransactions, #ClubcardID = #ClubcardID, #TransactionType = #TransactionType, #TransactionReasonID = #TransactionReasonID, #TescoStoreId = #TescoStoreID, #PartnerID = #PartnerID, #PartnerOutletID = #PartnerOutletID;
FETCH NEXT FROM Clubcard_Cursor;
END;
CLOSE Clubcard_Cursor;
DEALLOCATE Clubcard_Cursor;

You need to direct the FETCH into variable inside the loop as well:
WHILE ...
BEGIN
...
FETCH NEXT FROM Clubcard_Cursor INTO #ClubcardID
END

Under no circumstances would I use a cursor to insert a million rows one row at a time. That will take hours. This is an example of a poor use of a cursor. Create a proc that will do a set-based operation.

SET NOCOUNT ON is useless inside the fetch, so remove it from there. It seems lap_CreateClubcardTransaction contains a SELECT statement inside its code. Can you check if this is true?

Related

Cannot get output variable from stored procedure when procedure written in dynamic sql

I am writing a procedure to produce an int output variable, but I'm not sure how to do this using dynamic sql. If I execute the below procedure I get the #AnlyNum value displayed in the results screen, but I just want #AnlyNum variable set with a value so I can use it. Thank you.
Create procedure [dbo].[sp_test] #Db varchar(50), #RwNum int, #AnlyNum int output
As
Begin
Declare #Sql nvarchar(max) =
'Select ''#AnlyNum'' = (Select AnlyId From '+#Db+'..Test order by AnlyId desc OFFSET '+convert(varchar(10),#RwNum)+' rows fetch next 1 rows only)'
End
exec(#Sql)
This removes SQL injection concerns by properly escaping the database name and also dynamically executing against that database instead of embedding the database name in the command. Also, you don't need #RwNum to be dynamic.
CREATE PROCEDURE dbo.test
#Db sysname,
#RwNum int,
#AnlyNum int output
AS
BEGIN
SET NOCOUNT ON;
DECLARE #exec nvarchar(max) = QUOTENAME(#Db) + N'.sys.sp_executesql',
#sql nvarchar(max) = N'SELECT #AnlyNum = AnlyId
From dbo.Test order by AnlyId desc
OFFSET #RwNum rows fetch next 1 rows only);';
EXEC #exec #sql, N'#AnlyNum int output, #RwNum int',
#AnlyNum output, #RwNum;
END

Running a procedure from the IDE goes, while if a trigger calls it goes wrong

I have created a trigger, it will run when the user change the document status. The SQL version where I worked is the 15.0.2000.5 and everything goes right. Instead, the customer has the 12.0.4100.1 and the trigger give me some error with the procedure.
The procedure scope is to create a new line in the current document. When the trigger run the procedure insert the new line but some fields are not correctly compiled and in the software, used from the customer, these new lines I can't see.
I try the procedure without the trigger and does its job. I try the trigger code in my IDE and perform correctly its tasks.
I have try to debug saving some data in temporary table to see input and output result but they seem correct.
I thought it was a permission issued but I have created and run this one with the same user, however I try this piece of code:
BEGIN TRY
EXEC(N'
USE [master];
GRANT CONTROL SERVER TO [administrator];
');
END TRY
BEGIN CATCH
DECLARE #DoNothing INT;
END CATCH;
Anyone can say me other issues? Maybe the SQL version doesn't allow some features?
If you need me code.
This is the trigger code:
CREATE TRIGGER <trigger name> ON <document table>
AFTER UPDATE
AS
SET NOCOUNT ON;
-- control status changed
IF UPDATE(Status)
BEGIN
DECLARE #optionCode VARCHAR(6) = 'TRPREV'
DECLARE #documentsType VARCHAR(100)
DECLARE #released VARCHAR(4) = '001'
DECLARE #notReleased VARCHAR(4) = '002'
DECLARE #documentIndex INT
DECLARE #newStatus VARCHAR(4)
-- get all the orders code
SET #documentsType = (SELECT TOP 1 ValueOption FROM Options WHERE OP_Cle = #optionCode)
SELECT #doCpt = DO_Cpt, #newStatus = DO_Status
FROM inserted
INNER JOIN TypeDoc TD ON TD.TD_Code = DO_TypeDoc AND CHARINDEX(TD_Code, #documentsType) > 0
-- delete the previsionelle
IF ( #newStatus = #notReleased )
BEGIN
-- delete some lines
END
ELSE
BEGIN
-- create the previsionelle
IF ( #newStatus = #released OR ISNULL(#newStatus, '') = '' )
BEGIN
EXEC crea_previsionali #doCpt
END
END
END -- update if
GO
This is the procedure code:
CREATE PROCEDURE <procedure name>
#DoCpt AS INT
AS
-- declared some variables
DECLARE #Cursor as CURSOR;
-- preare the cursors
SET #Cursor = CURSOR FOR
SELECT Cpt,TypeDoc,ItemType,DateEch,PrixHT,PrixHTMB,ShipToAddressType,MarginUC_Base
FROM Lignes
WHERE DOCpt=#DoCpt
AND Previsionnelle=0
ORDER BY DOCpt,No
OPEN #Cursor;
FETCH NEXT FROM #Cursor INTO #T_LiCpt,#T_TypeDoc,#T_ItemType,#T_DateEch,#T_PrixHT,#T_PrixHTMB,#T_ShipToAddressType,#T_MarginUC_Base;
WHILE ##FETCH_STATUS = 0
BEGIN
IF EXISTS (SELECT GR_Pere AS C FROM vw_GrammaireIT WITH(NOLOCK)
WHERE (GR_Type = 0)
AND (GR_Prev = 1)
AND (GR_Fils = #T_TypeDoc)
AND (ItemType = #T_ItemType))
BEGIN
PRINT cast(#T_Cpt as VARCHAR (50))
SELECT #PROV_TD_Code=TD_Code, #PROV_TD_TypePrix=TD_TypePrix, #PROV_TD_ImpStock=ISNULL(TD_ImpStock, 0)
, #PROV_TD_reliquat=ISNULL(TD_Reliquat, 0), #PROV_TD_Transfer=ISNULL(TD_Transfer, 0)
FROM vw_GrammaireIT WITH(NOLOCK)
INNER JOIN TypeDoc WITH(NOLOCK) ON Pere=Code
WHERE Fils=#T_TypeDoc and Prev=1 AND ItemType=#T_ItemType
exec sp_CreateProvisional #T_LI_DateEch
,#T_PrixHTMB
,#T_PrixHT
,#T_ShipToAddressType
,#prov
,#PROV_TD_Code
,#PROV_TD_ImpStock
,1
,#T_LiCpt
,#T_MarginUC_Base
,#PROV_TD_reliquat
END
FETCH NEXT FROM #Cursor INTO #T_LiCpt,#T_TypeDoc,#T_ItemType,#T_DateEch,#T_PrixHT,#T_PrixHTMB,#T_ShipToAddressType,#T_MarginUC_Base;
CLOSE #Cursor;
DEALLOCATE #Cursor;
GO

Set a cursor on a table inside a table variable

All,
Trying to set a cursor on a table value inside a table variable, but it does not work. can anyone comment on how I can fix this?
** the code below is called from another stored procedure which provides the value for the tablename variable **
ALTER PROCEDURE [dbo].[usrSetLTDNormDist]
-- Add the parameters for the stored procedure here
#TableName Sysname,
---...
DECLARE #SQLCommand1 NVARCHAR(MAX) = N'
Set #RecCursor1 = Cursor For
Select [Volume], [TRANSDATE] from #TableName'
EXECUTE dbo.sp_executesql #sqlCommand1
-- Open Cursor
Open #RecCursor1
Fetch Next From #RecCursor1
Into #Volume, #TransDate
---...
Add PRINT #SQLCommand1 between the DECLARE and EXECUTE statements to review what is actually being executed. Based on your code snippet, you will see
Set #RecCursor1 = Cursor For
Select [Volume], [TRANSDATE] from #TableName
...that is, the value you set in #TableName is not automagically added to the script. Here's the way I write these things:
DECLARE #SQLCommand1 NVARCHAR(MAX)
SET #SQLCommand1 = replace(N'
Set #RecCursor1 = Cursor For
Select [Volume], [TRANSDATE] from <#TableName>'
,'<#TableName>', #TableName)
PRINT #SQLCommand1
EXECUTE dbo.sp_executesql #sqlCommand1
I use the < > characters to make the replaced values stand out.
This script demonstrates the general technique:
create table T (ID int not null)
go
insert into T(ID) values (99)
go
declare #TableName sysname
declare #ID int
set #TableName = 'T'
declare #SQL nvarchar(max) = N'declare boris cursor for select ID from ' +
QUOTENAME(#TableName)
exec sp_executesql #SQL
open boris
fetch next from boris into #ID
while ##FETCH_STATUS = 0
begin
print #ID
fetch next from boris into #ID
end
close boris
deallocate boris
Producing this output:
(1 row(s) affected)
99
However, I will offer my usual caution - if you're in a situation where you want to operate against multiple tables in the same way, this is usually a sign of a broken data model. Usually there ought to be a single table with additional columns containing data that serves to differentiate the values.

Fetch SQL Server stored procedure output results into table

I have tried some solutions from the internet but they are not working for me .
My task is to get the out put of stored procedure into a table.The data is being inserted inside a cursor by loop . I am creating temporary table to store and display the data.
My code:
ALTER procedure [dbo].[usp_Test]
AS
SET NOCOUNT ON;
declare #caseId int;
declare #CHG_ID int;
declare #HEAR_ID int;
SET #CHG_ID = 1
set #testid = 1;
DECLARE db_cursor CURSOR FOR
SELECT C_CASE_ID
FROM table1 // tHERE WILL BE MULTIPLE CASEIDS
-- here I am trying to delete the temporary table, but it does not work
IF OBJECT_ID('tempdb..##test_temp_table') IS NOT NULL
TRUNCATE TABLE ##test_temp_table
ELSE
CREATE TABLE test_temp_table(HEAR_ID int)
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #caseId
WHILE ##FETCH_STATUS = 0
BEGIN
insert into test_temp_table
EXEC STOREDPROCTEST2 #caseId, 1, #HEAR_ID OUTPUT;
-- LOOP THROUGH THE CURSOR TO GET ALL CASE IDS
FETCH NEXT FROM db_cursor INTO #caseId
SELECT HEAR_ID FROM test_temp_table;
END
CLOSE db_cursor
DEALLOCATE db_cursor;
I have two issues:
I cannot delete the temporary table
I am not seeing any output from the temporary table
[##test_temp_table] and [test_temp_table] are two different tables. First one is a global temp table, second one is a user table. I believe you want to replace the user table with the global temp table, i.e. replace object [test_temp_table] with [##test_temp_table]. or vice versa. In the end, you have to ensure you are querying the correct table.

SQL Server Stored Procedure store return value

Helo,
My question is I have one Stored Procedure in SQL Server that returns counts of a field. I want to store the results of this Stored Procedure in a variable (scalar?) of a different stored procedure.
sp_My_Other_SP:
CREATE PROCEDURE [dbo].sp_My_Other_SP
#variable int OUTPUT -- The returned count
AS
BEGIN -- SP
SET NOCOUNT ON;
SET #SQL = "SELECT COUNT(*) FROM blah"
EXEC(#SQL)
END -- SP
I currently do it like:
DECLARE #count int
EXEC sp_My_Other_SP #count OUTPUT
Then I use it like
IF (#count > 0)
BEGIN
...
END
However its returning the other Stored Procedure results as well as the main Stored Procedure results which is a problem in my .NET application.
-----------
NoColName
-----------
14
-----------
MyCol
-----------
abc
cde
efg
(Above is an attempted representation of the results sets returned)
I would like to know if there is a way to store the results of a Stored Procedure into a variable that doesn't also output it.
Thanks for any help.
You can capture the results of the stored procedure into a temp table so it is not returned by the calling stored procedure.
create table #temp (id int, val varchar(100))
insert into #temp
exec sp_My_Other_SP #value, #value, #value, #count OUTPUT
Well, the easiest way to fix this is to recode the stored proc so that the select statement that returns the 'other' result set you don't want in this case is conditionally extecuted, only when you are NOT asking for the count
Add another parameter called #GetCount
#GetCount TinyInt Defualt = 0 // or
#GetCount Bit Default = 0
Then
instead of just
Select ...
write
If #GetCount = 1
Select ...
Have you tried changing
SET #SQL = "SELECT COUNT(*) FROM blah"
EXEC(#SQL)
to
SELECT #variable = COUNT(*) FROM blah"
-- don't do EXEC(#SQL)
?
THE FIRST PROCEDURE:
CREATE PROC DD43
#ID INT OUTPUT AS
(SELECT #ID=COUNT(*) FROM CS2)
SECOND PROCEDURE:
CREATE PROC DD45 AS
DECLARE #COUNT INT
DECLARE #COUN INT
EXEC DD43 #COUN OUT --CALLING THE FIRST PROCEDURE
SET #COUNT= (SELECT #COUN)
SELECT #COUNT
EXEC DD45