SQL Unit Testing with TSQLUNIT - sql

I noticed something weird while unit testing an update/insert stored procedure using TSQLUNIT on SQL Server 2012. when I call Exec tsu_RunTests, my test procedure runs but with unexpected behaviour. the line in the code that calls my original stored procedure is executed but no actual updates or inserts made to the database table as expected. Is there a valid reason for this behaviour? Or is this a bug I need to pay much attention to? I notice that when I execute the same original stored procedure outside of the test procedure, it works fine.

You can use Default parameter for each stored procedure and set this #IsTest parameter to true when use these stored procedures in tsu_RunTests.
CREATE PROCEDURE orginal_proc
--#parameter_name
#IsTest BIT = 0
AS
if #IsTest <> 1 Begin
-- Test statements
End Else Begin
-- statements
End
GO
you also can use ##NESTLEVEL for check that your procedure execute directly or execute by other procedure.
CREATE PROCEDURE orginal_proc
--#parameter_name
AS
if ##NESTLEVEL <> 1 Begin
-- Test statements
End Else Begin
-- statements
End
GO
EDIT : Stored Procedure Code must be like below :
If ##NESTLEVEL <> 1 Print 'Befor Update Message'
If ##NESTLEVEL = 1 Begin
Update YourTable
Set ...
End
If ##NESTLEVEL <> 1 Print 'After Update Message'

Related

Stored procedure with a GO statement to free up resources

I have a stored procedure in a SQL Server 2019 database that does various checks for me when I run. This stored procedure contains several SELECT type statements - if the condition is true it will send an email.
This all works great when I run the whole stored procedure. As none of the statements are linked, I thought it would be more efficient if I ran each statement then had a GO command to release any memory or resources from previous SELECT.
But I can't do this as the GO does not work when I run me ALTER script on the stored procedure. It cuts off any lines after the GO. Is there any alternative T-SQL command that I can use similar to GO to free up resources?
ALTER PROCEDURE [dbo].[uspDataChecker]
AS
SET NOCOUNT OFF;
IF ((SELECT COUNT(DISTINCT GroupName) FROM tblSurveys) <> 5)
BEGIN
EXEC uspWebmasterSendEmail 'FAILED GroupName Check', 'GroupName does not contain 5 rows as expected'
END
-- I would like to put a "GO" statement here but when I
-- execute my ALTER script it chops off the below check
IF ((SELECT COUNT(*) FROM tblAccounts) <> 0)
BEGIN
EXEC uspWebmasterSendEmail 'FAILED Accounts Check', 'tblAccounts has rwos'
END

Why doesn't this catch the error in the stored procedure?

SQL Server 2014 (v12.0.5546) - I have a "master" stored procedure that I run a bunch of others from. If one errors out, I want it to print a line stating so.
I ran it today, and one of the stored procedures in the master stored procedure returned an error saying that the table insert I was trying had the wrong number of variables, but it did not print the error.
I thought that stored procedures returned 0 if successful, so anything other than that would mean an error. Am I wrong, or is there a flaw in my process?
FYI, I don't need it to stop running if it encounters an error, I just need it to spit out the error message so I know where it failed. This is going to grow to 20-30 stored procedures by the time it's all said and done.
Here is the master stored procedure:
ALTER PROCEDURE [dbo].[Master_CreateLoadTables]
AS
DECLARE #retval INT
-- Builds all tables required for the stored procedures
EXEC #retval = [BuildTables]
IF (#retval) = 0
BEGIN
SET #retval = 1
EXEC #retval = [Load_CustomerLookup]
IF (#retval) <> 0
PRINT 'Load of Customer Lookup Table Failed'
EXEC #retval = [Load_CustomerInvoices]
IF (#retval) <> 0
PRINT 'Load of Customer Invoice Tables Failed'
EXEC #retval = [Load_Payments]
IF (#retval) <> 0
PRINT 'Load of Payments Table Failed'
END
ELSE
PRINT 'Table Creation Failed'
I thought that stored procedures returned 0 if successful, so anything other than that would mean an error. Am I wrong, or is there a flaw in my process?
Stored procedures return whatever value you tell them to. If there is no return statement, then they return success, 0.
The generally accepted practice is to return 0 for success and an error code for failure. But that is not enforced.
You are referring to user stored procedures. You need to investigate how they work in your environment.
I also encourage you to put the body of the stored procedure in a begin/end block.
one of the stored procedures in the master stored procedure returned
an error saying that the table insert I was trying had the wrong
number of variables, but it did not print the error.
It seems this was a compilation error. The return code will not be set after compilation errors so the assigned variable will remain unchanged. For example:
CREATE PROC dbo.ExampleCompilationError
AS
SELECT * FROM dbo.ThisTableDoesNotExist;
GO
DECLARE #rc int = NULL;
EXEC #rc = dbo.ExampleCompilationError;
SELECT #rc;
GO
The return code is still NULL with this code.
You could surround each proc execution with TRY/CATCH, which will catch compilation errors and execution time errors in the inner scope:
BEGIN TRY
EXEC dbo.ExampleCompilationError;
END TRY
BEGIN CATCH
PRINT 'ExampleCompolationError failed';
END CATCH;

Main Stored Procedure to Execute another Proc depending on Input and output in a CSV

I have two procedures which basically give an Table output. I have the third Procedure which basically calls these two procedures and gives the output in an csv file format.
Can anyone help me in building this the right way. Below is something I am trying to do:
Each of the two Procedures gives out an output with like around 100k rows, I want to capture that and want to give the output here from the Main procedure in a csv file.(Please let me know if you need more info)
Create PROC MAIN
#InputParam int
AS
Begin
Set NOCOUNT ON;
BEGIN TRY
IF #InputParam not in (1,2)
BEGIN
Print 'Error Message'
END
Else
begin
IF #InputParam=1
BEGIN
Exec StoredProc1
Print 'Stored Procedure StoredProc1 ended at '+Convert(Varchar(25),GETDATE(),21);
End
Else
Begin
Print 'StoredProc1 does not exist'
END
IF #InputParam=2
BEGIN
Exec StoredProc2
Print 'Stored Procedure StoredProc2 ended at '+Convert(Varchar(25),GETDATE(),21);
End
Else
BEGIN
Print 'StoredProc2 does not exist'
END
END -- This is END for ELSE loop
END TRY
Begin Catch
Print 'Input Validation Catch Block with # '+ Convert(Varchar(5),ERROR_NUMBER())+' Msg: '+ERROR_MESSAGE();
End Catch
END
What you may want to try is to declare a table vairable in your main stored procedure. This table needs to match the output from the sub procedures exactly. The syntax is:
DECLARE #Temp TABLE(
Filed1 INT,
Field2 VARCHAR(100),
etc
)
Then you can execute your sub stored procedure and insert into the table you defined, like this:
INSERT INTO #Temp
EXEC StoredProc1
And finally, select from the #Temp
SELECT * FROM #Temp
You will obviously need to fit your exact requirements into this, but it should assist I hope
You cannot output to a CSV directly from a Stored Procedure without some form of code, so that really depends what you are developing with (ie what will call the stored procedure). You could perhaps build a SQL Job to output to CSV.

Conditionally create stored procedure using TSQL [duplicate]

This question already has answers here:
How do I conditionally create a stored procedure in SQL Server?
(11 answers)
Closed 7 years ago.
I'm writing a db update script which basically retrieve the current version number from the database then create a number of stored procedure if the version is valid. If the current version does not match the expected version then it should skip executing the code.
However I run into a problem when I write the script because CREATE PROCEDURE has to be the first statement in a batch, so it's not possible for me to insert if .. else statement before the create procedure statement.
I've also tried using GOTO but to no avail because GOTO doesn't span across multiple batches. Same thing applies to RETURN and RAISEERROR - the rest of the code will still execute.
Sample script:
IF #Version = '1.0' --doesn't work
BEGIN
CREATE PROCEDURE dbo.uspCreateAccount
AS BEGIN
--The rest of the code goes here
END
END
Can anyone provide some insight on this?
You can accomplish this using the exec functionality.
IF #Version = '1.0'
BEGIN
--Drop it if it already exists
IF OBJECT_ID('uspCreateAccount', 'P') IS NOT NULL
EXEC ('DROP PROCEDURE uspCreateAccount')
--Recreate it.
EXEC('
CREATE PROCEDURE uspCreateAccount
AS BEGIN
--The rest of the code goes here
END
')
END
You can use exec to run a SQL command in a new scope. The following snippet will run even when dbo.YourProc already exists, because the SQL command inside exec() will never be parsed in that case.
if not exists (select * from sys.procedures where name = 'YourProc')
exec ('create procedure dbo.YourProc as select 1 as a')
go
alter procedure dbo.YourProc
as
select ...
This construct creates an empty stub procedure if the procedure does not exist. If the procedure exists, it runs alter. So it preserves rights that have been granted on the procedure.

How to execute a stored procedure after it is created?

I'm trying to execute a stored procedure directly after its creation however it is not getting called. It looks like the stored procedure is not yet created during the execution call.
Here is how the script looks like:
CREATE PROCEDURE sp_Transfer_RegionData
AS
BEGIN
INSERT INTO Region (regionName)
SELECT column1
FROM openquery(ITDB, 'select * from db.table1')
END
EXEC sp_Transfer_RegionData
The script runs fine however the needed table is not populated. After replacing the execution part with:
IF OBJECT_ID('sp_Transfer_RegionData') IS NOT NULL
begin
exec [dbo].[sp_Transfer_RegionData]
print 'tada'
end
I could see that the stored procedure does not exist when it has to be executed. Couldn't find a solution for this in the internet...
So how to make the SQL script run sync so that the stored procedure would already exist during the execution part?
You need a GO after you created the SP otherwise you have created a recursive SP that calls itself "indefinitely" which is 32 times in SQL Server.
Maximum stored procedure, function, trigger, or view nesting level
exceeded (limit 32).
Try this:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE sp_Transfer_RegionData
AS
BEGIN
INSERT INTO Region (regionName)
SELECT column1
FROM openquery(ITDB, 'select * from db.table1')
END
GO
EXEC sp_Transfer_RegionData