debugging stored procedure in MS SQL server 2008 - sql

I have a stored procedure and I'm trying to debug it in the query window... when I open the stored procedure, I set some breakpoints in the code, but they never get hit.. In the code below, I can step through the USE line, then set ANSI_NULLS ON and then the code just says commands executed successfully, even though I have breakpoints set all throughout the code below it. Am I missing something?!
USE [Tool1]
GO
/****** Object: StoredProcedure [dbo].[aspdnsf_ImportProductPricing_XML] Script Date: 10/02/2014 09:38:17 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Alter proc [dbo].[aspdnsf_ImportProductPricing_XML]
#pricing ntext
AS
BEGIN
SET NOCOUNT ON
CREATE TABLE #tmp (ProductID int, VariantID int, KitItemID int, Name nvarchar(400), KitGroup nvarchar(800), SKU nvarchar(50), SKUSuffix nvarchar(50), ManufacturerPartNumber nvarchar(50), Cost money, MSRP money, Price money, SalePrice money, Inventory int)
DECLARE #hdoc int, #retcode int
EXEC #retcode = sp_xml_preparedocument
#hdoc OUTPUT,
#pricing
INSERT #tmp
SELECT *
FROM OPENXML(#hdoc, '/productlist/productvariant', 2)
WITH (ProductID int, VariantID int, KitItemID int, Name nvarchar(400), KitGroup nvarchar(800), SKU nvarchar(50), SKUSuffix nvarchar(50), ManufacturerPartNumber nvarchar(50), Cost money, MSRP money, Price money, SalePrice money, Inventory int)
UPDATE dbo.ProductVariant
SET Price = t.Price,
SalePrice = nullif(t.SalePrice,0),
Inventory = t.Inventory,
Cost = t.cost
FROM dbo.ProductVariant p
join #tmp t on p.ProductID = t.ProductID and p.VariantID = t.VariantID
WHERE KitItemID = 0
UPDATE dbo.KitItem
SET PriceDelta = t.Price
FROM dbo.KitItem k
join #tmp t on k.KitItemID = t.KitItemID
WHERE t.KitItemID > 0
exec sp_xml_removedocument #hdoc
DROP TABLE #tmp
END

When you debug store procedure you have to prepare exec statement for that procedre. You set breakpoint on it and then use Run button to start debugging. When you step into the procedure new window will be opened. In that window set breakpoints. They will work.

I gave up on debug in SQL years ago, and am sad to hear it has not improved in even the most recent versions. Here’s an overview of the tatcic I use when debugging stored procedures, which may or may not help you.
First, cut-and-paste the code to a new “working” window.
Run any necessary special formatting commands, e.g.
USE [Tool1]
GO
/****** Object: StoredProcedure [dbo].[aspdnsf_ImportProductPricing_XML] Script Date: 10/02/2014 09:38:17 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Next, comment out everything down through the create (or alter) procedure statement, like so:
--USE [Tool1]
--GO
--/****** Object: StoredProcedure [dbo].[aspdnsf_ImportProductPricing_XML] Script Date: 10/02/2014 09:38:17 ******/
--SET ANSI_NULLS ON
--GO
--SET QUOTED_IDENTIFIER ON
--GO
--Alter proc [dbo].[aspdnsf_ImportProductPricing_XML]
-- #pricing ntext
If there are parameters, plop down a DECLARE statement in front of them, and remove any output settings.
Replace the AS statement with SET values for each parameter, and use these to set testing values
From there, scroll down through a portion of code, highlight that point and all preceding text (shift + control + home), and execute (F5), and observe what happens. Insert PRINT and SELECT statements and repeat as necessary, slowly increasing how much code gets executed with each call, or when possible running only a few selected lines of code.
There are of course a zillion gotchas to this (which is why it would be really nice to have real world debug in SQL—and I don’t see this happening, in part because of #Temp tables, and in part because of BEGIN TRANSACTION / EXECUTE / GOTO lunch / ROLLBACK), but I digress. One such gotcha here is your #Temp table. On the first pass it gets created, and on all subsequent passes you’ll get a “table already exists” error. Lazy (because it doesn't work the first time you run it) work-around:
DROP TABLE #tmp
CREATE TABLE #tmp (ProductID int, <etc>)
Fussy work-around:
IF object_id('tempdb..#Tmp') is not null
DROP TABLE #tmp
CREATE TABLE #tmp (ProductID int)
sp_xml_preparedocument / sp_xml_removedocument is going to be another gotcha. Not sure how to deal with that, we gave that up for Xquery years ago.

Related

How to use multiple update query for single table on same store procedure

I have stored procedure which has
1) update query and I want to add the
2) update query in the same store procedure. Is that possible that I can use the below code? or Can anyone help me how can I use multiple update query for the same table?
USE [Databse]
GO
/****** Object: StoredProcedure [dbo].[sp_Tableupdate]
Script Date: 5/19/2017 8:12:11 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_Tableupdate]
#IncomeID int,
#MemberID int,
#ParticipantID int,
#IncomeTypeID int,
#PaymentFrequencyTypeID int,
#Employer varchar(max),
#Occupation varchar(max),
#TypeOfBusiness varchar(max),
#GrossAmount decimal(18,2),
#Verified bit
AS
BEGIN
1)UPDATE Table SET
MemberID=#MemberID,
ParticipantID=#ParticipantID,
IncomeTypeID=#IncomeTypeID,
PaymentFrequencyTypeID=#PaymentFrequencyTypeID,
Employer=#Employer,
Occupation=#Occupation,
TypeOfBusiness=#TypeOfBusiness,
GrossAmount=#GrossAmount,
Verified=#Verified
WHERE IncomeID=#IncomeID
2)Update table set ParticipantID = #ParticipantID where MemberID = #MemberID
END
This is definitely possible, you can set as many UPDATE statements in their as you want.
Do note that your last update statement will overwrite your first update statements, if the same records are touched.
Best practice would be to end each statement with a semicolon e.g. ';').
USE [Databse]
GO
/****** Object: StoredProcedure [dbo].[sp_Tableupdate]
Script Date: 5/19/2017 8:12:11 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_Tableupdate]
#IncomeID int,
#MemberID int,
#ParticipantID int,
#IncomeTypeID int,
#PaymentFrequencyTypeID int,
#Employer varchar(max),
#Occupation varchar(max),
#TypeOfBusiness varchar(max),
#GrossAmount decimal(18,2),
#Verified bit,
#run_proc int
AS
BEGIN
IF(#run_proc = 1)
BEGIN
PRINT 'Running Update 1';
UPDATE Table SET
MemberID=#MemberID,
ParticipantID=#ParticipantID,
IncomeTypeID=#IncomeTypeID,
PaymentFrequencyTypeID=#PaymentFrequencyTypeID,
Employer=#Employer,
Occupation=#Occupation,
TypeOfBusiness=#TypeOfBusiness,
GrossAmount=#GrossAmount,
Verified=#Verified
WHERE IncomeID=#IncomeID;
END
ELSE IF(#run_proc = 2) BEGIN
PRINT 'Running Update 2';
Update table set ParticipantID = #ParticipantID where MemberID = #MemberID
END
END

Unable to pull out resetSet for insert within stored procedure

I have been looking online for a few days to find a solution and
I may be asking the wrong questions.
I have the following stored proc which on insertion of a row to a db I want to get back the output int (#outResult). This is the stored proc :
USE [DB1]
GO
/****** Object: StoredProcedure [dbo].[storedProc1] Script Date: 04/12/2016 10:16:23 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[storedProc1]
-- Add the parameters for the stored procedure here
#inParam nvarchar(max),
#outResult int = 0 OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
IF NOT EXISTS
(
SELECT ID
FROM dbo.table1
WHERE Field1 = #inParam
)
Insert into [DB1].[dbo].[table1]
(
Field1
)
Values (
#inParam
)
SET #outResult = SCOPE_IDENTITY()
END
When I run the following SQL and try to retrieve the resultSet :
SELECT * FROM (EXEC storedProc1 'field1')
I get the following error:
"Incorrect syntax near the keyword 'exec'"
Maybe I am approaching this problem wrong from the first place?
I will continue to look into this and provide a solution if I find one.Any ideas?
To get the value of the output parameter you need to supply the call to the SP with an output argument. You do that by specifying the OUTPUT option on the second parameter.
DECLARE #returned_ID INT;
EXEC storedProc1 #inParam = 'field1',
#outResult = #returned_ID OUTPUT
SELECT #returned_ID
If you want to retrieve just the out parameter, then You can read it as :
DECLARE #output int
EXEC storedProc1 'field1',#output OUTPUT
SELECT #output

Trigger Failing when calling Stored Procedure

I am truly hoping someone can help me out...
I have a trigger to handle the insert of a new record to a table. This trigger, as you will see below, inserts a record into another table, which in turns executes a trigger on that table, that calls a stored procedure (I tried to do it within the trigger itself, but it failed and was difficult to test where it was failing, so I moved it into its own little unit.)
Within the stored procedure, there is a call to extract information from the Active Directory database (ADSI) and update the newly inserted record. However, this is where it fails when called by the trigger. When I call it by simply executing it, and passing along the record to be updated, it works great... Can anyone point me in the right direction? Please!!!
Trigger #1 in YYY
USE [YYY]
GO
/****** Object: Trigger [dbo].[NewCustodian] Script Date: 08/04/2014 09:38:11 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[NewCustodian]
ON [YYY].[dbo].[Custodians]
AFTER INSERT
AS BEGIN
SET NOCOUNT ON;
DECLARE #CaseID varchar(20);
DECLARE DBcursor CURSOR FOR
SELECT [XXX].[dbo].[tblCase].CaseID from [XXX].[dbo].[tblCase] Where [XXX].[dbo].[tblCase].SQLSVR_Case_ID = 'YYY';
Open DBcursor; FETCH DBCursor into #CaseID;
CLOSE DBcursor; DEALLOCATE DBcursor;
DECLARE #NAME varchar(255);
DECLARE #TAG varchar(255);
SELECT #NAME = name FROM inserted;
SELECT #TAG = tag FROM inserted;
IF NOT EXISTS (Select eID from [XXX].[dbo].[tblNames]
WHERE eID = #TAG and CaseID = #CaseID)
BEGIN
INSERT INTO [XXX].[dbo].[tblNames] (CaseID, Name, eID)
Values (#CaseID, #NAME, #Tag);
END
END
Trigger #2 in XXX
USE [XXX]
GO
/****** Object: Trigger [dbo].[tblNames_New] Script Date: 08/04/2014 08:56:43 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:
-- Create date:
-- Description:
-- =============================================
ALTER TRIGGER [dbo].[tblNames_New]
ON [XXX].[dbo].[tblNames]
AFTER INSERT
AS BEGIN
SET NOCOUNT ON;
DECLARE #NamesID varchar(10)
DECLARE #TAG varchar(10);
DECLARE #return_value int
SELECT #NamesID = namesID FROM inserted
EXEC dbo.UpdateNames #NamesID;
End
Stored procedure:
USE [XXX]
GO
/****** Object: StoredProcedure [dbo].[UpdateNames] Script Date: 08/04/2014 08:14:52 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:
-- Create date:
-- Description:
-- =============================================
ALTER PROCEDURE [dbo].[UpdateNames]
#NamesID int
AS
BEGIN
SET FMTONLY OFF;
SET NOCOUNT ON;
DECLARE #eID varchar(10);
DECLARE #TAG varchar(10);
DECLARE #SQL nvarchar(555);
DECLARE #DBresults as table (
eID nvarchar(100),
mobile nvarchar(100),
mail nvarchar(100),
phone nvarchar(100),
name nvarchar(50),
legacyExchangeDN nvarchar(100),
Title nvarchar(100),
homeDirectory nvarchar(100));
DECLARE #mobile nvarchar(100)
DECLARE #mail nvarchar(100)
DECLARE #phone nvarchar(100) = 'Error'
DECLARE #name nvarchar(100)
DECLARE #legacyExchangeDN nvarchar(100)
DECLARE #Title nvarchar(100) = 'Error'
DECLARE #homeDirectory nvarchar(100)
SET #eID = (Select eID from [XXX].[dbo].[tblNames] Where NamesID = #NamesID)
SET #SQL = N'SELECT * FROM OpenQuery ( ADSI, ''SELECT homeDirectory,Title,legacyExchangeDN,displayName, telephoneNumber, mail, mobile,samAccountName
FROM ''''LDAP://domain.com''''
WHERE objectClass = ''''User'''' and samAccountName = ''''' + #eID+ ''''''') As tblADSI'
INSERT INTO #DBresults
EXEC sp_executesql #SQL
DECLARE DBcursor CURSOR FOR
SELECT * from #DBresults;
Open DBcursor; FETCH DBCursor into #eID, #mobile, #mail, #phone, #Name, #legacyExchangeDN, #Title, #homeDirectory;
CLOSE DBcursor; DEALLOCATE DBcursor;
UPDATE XXX.dbo.tblNames
SET Job_Title = #Title,
Phone = #Phone
Where NamesID = #NamesID;
END
As I said in my comment - a trigger should be extremely small, nimble, lean - do not do any extensive and time-consuming processing inside a trigger, and avoid anything that would cause performance bottlenecks, especially cursors!
The reason for this is the fact that a trigger will be triggered whenever an INSERT operation happens, you have no control over when and how many times it gets called. The main app will wait and hang while the trigger is at work - so therefore, don't make this a long time - return very quickly from your trigger to go on with your main app.
My approach would be:
create a new separate table where you insert some key pieces of information into from your first original trigger
CREATE TABLE NewCustodianInserted
(
ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
CaseID VARCHAR(20),
Tag VARCHAR(255),
Handled BIT DEFAULT (0)
);
change your original trigger on the Custodians table to just insert those key pieces of information into your new "command" table:
CREATE TRIGGER [dbo].[NewCustodian]
ON [YYY].[dbo].[Custodians]
AFTER INSERT
AS BEGIN
SET NOCOUNT ON;
-- insert key pieces about the new custodian into "command" table
INSERT INTO dbo.NewCustodianInserted (CaseID, Tag)
SELECT i.CaseId, i.Tag
FROM Inserted i
WHERE NOT EXISTS (SELECT * FROM [XXX].[dbo].[tblNames] WHERE eID = i.Tag AND CaseID = i.CaseID)
END
in a separate process, e.g. a SQL Server Agent job that is scheduled to run every 5 mînutes (or whatever makes sense for your application), read the "command" table, get the new custodians to handle, call that long-running stored procedure updating Active Directory from it. Here, since this runs asynchronously from your main application, it's ok to use a cursor which you almost have to since you want to call a stored procedure for every row in your new table.
CREATE PROCEDURE HandleNewCustodians
AS
BEGIN
SET NOCOUNT ON;
DECLARE #CaseID VARCHAR(20);
DECLARE #Tag VARCHAR(255);
DECLARE #NamesID varchar(10);
DECLARE CustodianCursor CURSOR FAST_FORWARD
FOR
SELECT CaseID, Tag FROM dbo.NewCustodianInserted WHERE Handled = 0
OPEN CustodianCursor
FETCH NEXT FROM CustodianCursor INTO #CaseID, #Tag;
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #NamesID = NameID
FROM [XXX].[dbo].[tblNames] WHERE eID = #Tag AND CaseID = #CaseID
EXEC dbo.UpdateNames #NamesID;
FETCH NEXT FROM CustodianCursor INTO #CaseID, #Tag;
END
CLOSE CustodianCursor;
DEALLOCATE CustodianCursor;
END

Unable to call stored procedure within stored procedure

I have three stored procedures A, B, C
and definition of A is like
StoredProcedure A
As
Begin
--Some Stuff
Exec DBO.B [Derived Conitions]
Exec DBO.C [Derived Conitions]
END
but whenever I tried to execute the stored procedure A, at parsing time it give waring;
The module 'A' depends on the missing object 'B'. The module will still be created;
however, it cannot run successfully until the object exists.
The module 'A' depends on the missing object 'C'. The module will still be created;
however, it cannot run successfully until the object exists.
At execution time it throws exception
Could not find stored procedure 'dbo.B'.
Could not find stored procedure 'dbo.C'.
I found so many answers for calling a stored procedure with in stored procedure, but none of them worked for me.
You certainly can execute multiple procedures from within a single SP. You can even us the results from 1 SP as parameters in another.
In your specific case I suspect that there is a permissions / security or collation error which is stopping you from access the B and C stored procs.
Here is an example of SP chaining at work.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[DerivedProcedures]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Temporary table used to store results from SP1
DECLARE #Results_ForStoredProcedure1 TABLE
(
[SPID] INT,
[Status] NVARCHAR(50),
[Login] NVARCHAR(50),
[HostName] NVARCHAR(50),
[BlkBy] NVARCHAR(5),
[DBName] NVARCHAR(50),
[Commad] NVARCHAR(50),
[CPUTime] INT,
[DiskIO] INT,
[LastBatch] NVARCHAR(50),
[ProgramName] NVARCHAR(50),
[SPID2] INT,
[RequestId] INT
)
-- Execute SP1
INSERT INTO #Results_ForStoredProcedure1
EXEC sp_who2
-- Temporary table to store the results from SP2
DECLARE #Results_ForStoredProcedure2 TABLE
(
[DatabaseName] NVARCHAR(50),
[DatabaseSize] INT,
[Remarks] NVARCHAR(50)
)
-- Execute SP2
INSERT INTO #Results_ForStoredProcedure2
EXEC sp_databases
-- do something with both SP results
SELECT DISTINCT SP2.*
FROM #Results_ForStoredProcedure1 AS SP1
INNER JOIN #Results_ForStoredProcedure2 AS SP2 ON SP2.DatabaseName = SP1.DBName
WHERE SP1.DBName IS NOT NULL
END
GO
-- TEST
EXECUTE [dbo].[DerivedProcedures]
Perhaps, it sounds hilarious but I was getting the mentioned issue as I was using the wrong DB name (for example-Use 'XYZ'). Actually, in my case I was transferring a SP from one environment to another but after doing so I would not change the corresponding DB name .Due to which I was getting the error as the SPs which were involved were present in different DBs in the dissimilar environment.
In nutshell,please check the DB name which should be the very first line of your SP.
For example- Use 'XYZ'.

Invalid Object Name - Stored Procedure

I am creating a stored procedure in SQL Server via SSMS.
I have written the stored procedure below, however when I click execute it am given the error:
Msg 208, Level 16, State 6, Procedure NewQuestion, Line 11
Invalid object name 'hgomez.NewQuestion'.
the table is ownership is correct. (hgomez.Questions)
USE [devworks_oscar]
GO
/****** Object: StoredProcedure [hgomez].[NewQuestion] Script Date: 10/23/2011 23:55:08 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [hgomez].[NewQuestion]
(
#QUESTIONNAME nvarchar(50),
#QUESTION_ID int OUTPUT
)
AS
/* SET NOCOUNT ON */
INSERT INTO [Questions] (QuestionText) VALUES (#QUESTIONNAME)
SET #QUESTION_ID = SCOPE_IDENTITY();
RETURN
Thanks in advance
I was a fan of always prepending my CREATE statements with an explicit check for existence and dropping if it was found.
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'NewQuestion' AND ROUTINE_SCHEMA = 'hgomez')
BEGIN
DROP PROCEDURE hgomez.NewQuestion
END
GO
-- this is always a CREATE
CREATE PROCEDURE [hgomez].[NewQuestion]
(
#QUESTIONNAME nvarchar(50),
#QUESTION_ID int OUTPUT
)
AS
/* SET NOCOUNT ON */
INSERT INTO [Questions] (QuestionText) VALUES (#QUESTIONNAME)
SET #QUESTION_ID = SCOPE_IDENTITY();
RETURN
That can be a bit of hassle with regard to permissions so others use an approach wherein they create a stub method only to immediately ALTER it.
IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'NewQuestion' AND ROUTINE_SCHEMA = 'hgomez')
BEGIN
EXEC ('CREATE PROCEDURE hgomez.NewQuestion AS SELECT ''stub version, to be replaced''')
END
GO
-- This is always ALTER
ALTER PROCEDURE [hgomez].[NewQuestion]
(
#QUESTIONNAME nvarchar(50),
#QUESTION_ID int OUTPUT
)
AS
/* SET NOCOUNT ON */
INSERT INTO [Questions] (QuestionText) VALUES (#QUESTIONNAME)
SET #QUESTION_ID = SCOPE_IDENTITY();
RETURN
This script tries to modify a procedure that already exists; it doesn't create the procedure.
To create the procedure use CREATE PROCEDURE
CREATE PROCEDURE [hgomez].[NewQuestion]
Once the procedure exists, you can modify its definition by using ALTER PROCEDURE
ALTER PROCEDURE [hgomez].[NewQuestion]
This solution https://stackoverflow.com/a/26775310/2211788 explained
If you drop and re-create a stored procedure it gets a new objectid - the list of stored procedures in SSMS is linked to the id it knows at the time the list was built. If you re-create it but don't refresh the stored procedures folder then any attempts to edit it will indicate the procedure is not found as the id has changed.
This happened to me once when I had two instances of SSMS open and I was working on the one I opened first. Closed them both down, reopened and it worked fine.