Will all transaction in this stored procedure be rolled back - sql-server

I have created a stored procedure (shown below) in SQL Server and tried to include a Rollback Transaction as I need to have a "stored procedure that has a transaction around it, so that if/when it fails all inserts will be rolled back."
I am unsure if this work or not, or will work, I cannot test yet as only developing locally, but wondered if someone wouldn't mind looking over the Rollback Transaction part of the stored procedure and advise if on the right path?
USE AutomatedTesting
GO
ALTER PROCEDURE [dbo].[spInsertTestCases]
(#AddedTFS INT,
#Scenario NVARCHAR(500),
#TargetTableName NVARCHAR(100),
#TargetFieldName NVARCHAR(100),
#ExpectedResult NVARCHAR(100),
#TargetTableDBName NVARCHAR(100),
#TargetTableSchema NVARCHAR(100),
#TargetFieldIsDateTime NVARCHAR(1),
#TestCaseIdentifiers dbo.TestCaseIdentifiers READONLY ) -- can only be READONLY. meaning you cannot amend the param
/* #TestCaseIdentifiers var will be prepopulated
TestDataIdentifiersNEW is a custom data type which has fields (TestSequence ColumnName ColumnValue IsAlphaNumeric)
so stored procedure is called like:
EXEC [dbo].[spTest_UserDefinedDatatype] 'param1','param2' #temp_testdata
#temp_testdata will already be defined and popualted(INSERT INTO ) before exec to add in 1 to many rows.
for example:
ColumnName ColumnValue
PATIENTID 123456
SOURCESYS PAS
in simple terms above EXEC is:
EXEC [dbo].[spTest_UserDefinedDatatype] 'param1','param2' 'PATIENTID 123456'
'SOURCESYS PAS'
*/
AS
BEGIN TRY
BEGIN TRANSACTION
BEGIN
--DECLARE #TableNameUpdate SYSNAME = #TargetTableName
--DECLARE #CDI SYSNAME = REPLACE(#TargetTableName,'CDO','CDI') -- so if targettablename param is CDO then swap it to CDI. why?
DECLARE #sql VARCHAR(MAX) = ' INSERT INTO [dbo].[TestCasesIdentifier] ([TestCaseId], [TestCaseSequence], [FieldName], [FieldValue], [AlphaNumeric]) VALUES '
DECLARE #i INT = 1
DECLARE #TableNameUpdate SYSNAME = #TargetTableName
DECLARE #CDI SYSNAME = REPLACE(#TargetTableName,'CDO','CDI')
DECLARE #ColName SYSNAME
DECLARE #Ret NVARCHAR(256)
DECLARE #sql2 NVARCHAR(MAX)
DECLARE #TestCaseID INT = -1 --does this need default variable?
DECLARE #ErrorCode INT = ##error
DECLARE #TestSequence INT
DECLARE #ColumnName VARCHAR(100)
DECLARE #ColumnValue VARCHAR(100)
DECLARE #IsAlphaNumeric BIT
DECLARE #TableTestSequence INT = ISNULL((SELECT MAX([TableTestSequence]) + 1 FROM TestCases WHERE #TargetTableName = [TargetTableName]), 1)
-- INSERT into TestCases. 1 record
-- An assumption that a number of fields will have defaults on them - if not, extra fields will need adding
INSERT INTO [dbo].[TestCases] ([AddedTFS], [TableTestSequence], [Scenario],
[TargetTableName], [TargetFieldName], [ExpectedResult],
[TargetTableDBName], [TargetTableSchema], [TargetFieldIsDateTime])
VALUES (#AddedTFS, -- AddedTFS (The TFS Number of the Development carried out)
ISNULL((SELECT MAX([TableTestSequence]) + 1 -- TableTestSequence (Generates the next Sequence Number for a Table)
FROM TestCases -- if table doesnt exist in TestCases then sets to 1
WHERE #TargetTableName = [TargetTableName]), 1),
#Scenario, -- Scenario (A description of the scenario use GIVEN and WHERE)
#TargetTableName, -- TargetTableName (References the Target Table entered at the top of this SQL - SET #TableName = 'CDO_APC_ELECTIVE_ADMISSION_LIST')
#TargetFieldName, -- TargetFieldName (The Field in which we want to test)
#ExpectedResult, -- ExpectedResult (The expected output/result of the field in which we want to test)
#TargetTableDBName, -- The DB to be used
#TargetTableSchema, -- the schema to be used
#TargetFieldIsDateTime) ---- 1 = Yes, 0 = No (Is Target field a datetime field)
-- Grab the identity value just generated by the last statement and the last error code generated
-- in order to reference TestCases PK when adding to TestCaseIdentifiers
SELECT #TestCaseID = SCOPE_IDENTITY(), #ErrorCode = ##error
IF #ErrorCode = 0 --OR #TestCaseID <> -1 -- #ErrorCode <> 0 if error then back out testcases INSERT? surely should use BEGIN/ROLLBACK tran
--IF #ErrorCode = 0 OR #TestCaseID <> -1
-- If there was no error creating the TestCase record, create the records for the WHERE clause
BEGIN
/*
rollback insert if no matching records
rollback insert if SQL returns more than 1 record
return error message to user
*/
SELECT
ic.index_column_id, c.name
INTO #tmp
FROM sys.indexes i
JOIN sys.index_columns ic ON i.object_id = ic.object_id
AND i.index_id = ic.index_id
JOIN sys.columns c ON c.column_id = ic.column_id
AND c.object_id = ic.object_id
JOIN sys.tables t ON c.object_id = t.object_id
WHERE t.name = #CDI
AND i.is_primary_key = 1
IF (SELECT COUNT(*) FROM #TestCaseIdentifiers) = 0
--IF #PKValues IS NULL
BEGIN
WHILE #i <= (SELECT COUNT(*) FROM #tmp)
BEGIN
SELECT #ColName = [name]
FROM #tmp
WHERE index_column_id = #i
-- if #expectedvalue IS NULL
SET #sql2 = 'SELECT TOP 1 #RetvalOut = ' + QUOTENAME(#ColName) + ' FROM ' + QUOTENAME(#CDI) + ' ORDER BY NEWID()'
-- else
-- SET #sql2 = ''
EXECUTE sp_executesql #command = #sql2, #ParmDefinition = N'#RetvalOut NVARCHAR(MAX) OUTPUT', #retvalOut = #Ret OUTPUT
SET #sql += '(' + CONVERT(VARCHAR(100),#TestCaseID) + ',' + CONVERT(VARCHAR(10),#i) + ',''' + #ColName + ''',''' + #Ret + ''',1),'
SET #i+=1
SELECT #sql = REVERSE(SUBSTRING(REVERSE(#sql),2,8000))
PRINT #sql
EXEC #sql
END
END
ELSE
BEGIN
--PRINT 'got here'
DECLARE csr_TestCaseIdentifierInsert CURSOR FOR
SELECT [TestSequence],[ColumnName],[ColumnValue],[IsAlphaNumeric]
FROM #TestCaseIdentifiers
ORDER BY [TestSequence]
OPEN csr_TestCaseIdentifierInsert
FETCH NEXT FROM csr_TestCaseIdentifierInsert INTO #TestSequence, #ColumnName, #ColumnValue, #IsAlphaNumeric
WHILE ##fetch_status = 0
BEGIN
INSERT INTO [dbo].[TestCasesIdentifier]
([TestCaseId],
[TestCaseSequence],
[FieldName],
[FieldValue],
[AlphaNumeric])
VALUES
(#TestCaseID, #TestSequence, #ColumnName, #ColumnValue,#IsAlphaNumeric)
FETCH NEXT FROM csr_TestCaseIdentifierInsert INTO #TestSequence, #ColumnName, #ColumnValue, #IsAlphaNumeric
END
CLOSE csr_TestCaseIdentifierInsert
DEALLOCATE csr_TestCaseIdentifierInsert
END -- loop to add records to testcasesidentifier
END
END
COMMIT
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN
DECLARE #ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE()
DECLARE #ErrorSeverity INT = ERROR_SEVERITY()
DECLARE #ErrorState INT = ERROR_STATE()
-- Use RAISERROR inside the CATCH block to return error
-- information about the original error that caused
-- execution to jump to the CATCH block.
RAISERROR (#ErrorMessage, #ErrorSeverity, #ErrorState);
END CATCH

You are almost there. I usually wrap the stored proc code within a BEGIN..END block as well, then next comes the most important part: you must add SET XACT_ABORT ON; before your TRY..CATCH and BEGIN TRAN, as SQL Server defaults the XACT_ABORT to OFF. Otherwise not everything will be rolled back.
Example setup:
CREATE PROCEDURE dbo.uspMyTestProc
AS
BEGIN
SET NOCOUNT, XACT_ABORT ON;
BEGIN TRY
BEGIN TRANSACTION;
-- Do your magic stuff here before committing...
COMMIT;
END TRY
BEGIN CATCH
IF ##trancount > 0
ROLLBACK TRANSACTION;
-- Add extra error logging here if you want...
END CATCH;
END;
GO
Also, if you want to add a possible stacktrace if you are using nested procedures et cetera you might want to consider using a generic error handler à la Erland Sommerskog. We adapted this approach completely. See for more details How to handle Transaction in Nested procedure in SQL server?

Related

Tuning Stored Procedure

How can you improve this without using a cursor? I was thinking using table variable would help, but am I going right direction doing so? I have omitted cursor and try to do it with table variable. Please help, here is the code.
IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id(N'[dbo].[BatchProcessBridge_CustomerEvent]') AND [xtype] IN (N'P'))
BEGIN
DROP PROCEDURE [dbo].[BatchProcessBridge_CustomerEvent]
END
GO
CREATE PROCEDURE [dbo].[BatchProcessBridge_CustomerEvent]
(
#BatchJobTable Bridge_CustomerEventBatchJobTable READONLY,
#Name VARCHAR(50)
)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Lsn BINARY(10),
DECLARE #SeqVal BINARY(10),
DECLARE #Action VARCHAR(300),
DECLARE #CustId VARCHAR(MAX)
--using tabel variable. Cursor gives bad performance.
DECLARE #TEMP_TABLE TABLE ( [Lsn] BINARY(10), [SeqVal] BINARY(10), [Action] VARCHAR(300), [CustId] VARCHAR(MAX))
INSERT INTO #TEMP_TABLE
SELECT Lsn, SeqVal, [Action], [CustId] FROM #BatchJobTable
--DECLARE GetBatchJobCursor CURSOR FAST_FORWARD
--FOR
--SELECT Lsn, SeqVal, [Action], [CustId] FROM #BatchJobTable
--OPEN GetBatchJobCursor
--FETCH NEXT FROM GetBatchJobCursor INTO #Lsn, #SeqVal, #Action, #CustId
--WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN TRY
BEGIN TRANSACTION
IF (#Action = 'create')
BEGIN
-- Create.
INSERT INTO [Bridge_Customer]
(
[CustId]
,[PersonId]
,[DisplayName]
,[CreatedDate]
,[ModifiedDate]
)
SELECT
[CustId]
,[PersonId]
,[DisplayName]
,[CreatedDate]
,[ModifiedDate]
FROM
#BatchJobTable
WHERE
(Lsn = #Lsn) AND (SeqVal = #SeqVal)
END
ELSE IF (#Action = 'update')
BEGIN
-- Update.
UPDATE [Target]
SET
[Target].[CustId] = [Ref].[CustId]
,[Target].[PersonId] = [Ref].[PersonId]
,[Target].[DisplayName] = [Ref].[DisplayName]
,[Target].[CreatedDate] = [Ref].[CreatedDate]
,[Target].[ModifiedDate] = [Ref].[ModifiedDate]
FROM
[dbo].[Bridge_Customer] AS [Target]
INNER JOIN
(SELECT * FROM #BatchJobTable WHERE (Lsn = #Lsn) AND (SeqVal = #SeqVal)) AS [Ref]
ON
([Target].[CustId] = [Ref].[CustId])
END
ELSE IF (#Action = 'delete')
BEGIN
DELETE FROM [dbo].[Bridge_Customer] WHERE [CustId] = #CustId
END
-- Update last processed event.
EXEC [dbo].[UpdateLastProcessedEvent]
#Name = #Name,
#Lsn = #Lsn,
#SeqVal = #SeqVal
COMMIT TRANSACTION
END TRY
BEGIN CATCH
DECLARE #ErrorMessage NVARCHAR(4000);
DECLARE #ErrorSeverity INT;
DECLARE #ErrorState INT;
SELECT
#ErrorMessage = ERROR_MESSAGE(),
#ErrorSeverity = ERROR_SEVERITY(),
#ErrorState = ERROR_STATE();
-- Use RAISERROR inside the CATCH block to return error
-- information about the original error that caused
-- execution to jump to the CATCH block.
RAISERROR (#ErrorMessage, -- Message text.
#ErrorSeverity, -- Severity.
#ErrorState -- State.
);
ROLLBACK TRANSACTION
END CATCH
--FETCH NEXT FROM GetBatchJobCursor INTO #Lsn, #SeqVal, #Action, #CustId
END
--CLOSE GetBatchJobCursor
--DEALLOCATE GetBatchJobCursor
END
GO
A cursor is not necessary here; this is just basic SQL. Forgive any mistakes with my code as you haven't provided any DLL but I'm pretty sure you can just do this:
IF (#Action = 'create')
INSERT INTO Bridge_Customer
(
CustId
,PersonId
,DisplayName
,CreatedDate
,ModifiedDate
)
SELECT
CustId
,PersonId
,DisplayName
,CreatedDate
,ModifiedDate
FROM #BatchJobTable
ELSE IF (#Action = 'update')
UPDATE tgt
SET tgt.CustId = Ref.CustId
,tgt.PersonId = Ref.PersonId
,tgt.DisplayName = Ref.DisplayName
,tgt.CreatedDate = Ref.CreatedDate
,tgt.ModifiedDate = Ref.ModifiedDate
FROM dbo.Bridge_Customer AS tgt
INNER JOIN #BatchJobTable AS ref
ON (tgt.CustId = Ref.CustId)
ELSE IF (#Action = 'delete')
DELETE FROM dbo.Bridge_Customer
WHERE CustId IN (SELECT CustId FROM #BatchJobTable);
Personally, I would split this into three stored and call whichever one from the application layer. What you are doing is known as a "Catch All query" which is fine but, if you must go that route, read this: Catch All Queries (Gail Shaw)

TSQL Transaction behaviour with disconnected queries - dynamic SQL

I have the below stored procedure, that dynamically calls a list of stored procedures. It's been in place for a few months and has been running fine (unfortunately my access to the server is pretty restricted so couldn't manage this any other way)
Alter Proc [Process].[UspLoad_LoadController]
(
#HoursBetweenEachRun Int
)
As
Begin
--find all procedures that need to be updated
Create Table [#ProcsToRun]
(
[PID] Int Identity(1 , 1)
, [SchemaName] Varchar(150)
, [ProcName] Varchar(150)
);
Insert [#ProcsToRun]
( [SchemaName]
, [ProcName]
)
Select [s].[name]
, [p].[name]
From [sys].[procedures] [p]
Left Join [sys].[schemas] [s]
On [s].[schema_id] = [p].[schema_id]
Where [s].[name] = 'Process'
And [p].[name] Like 'UspUpdate%';
Declare #MaxProcs Int
, #CurrentProc Int = 1;
Select #MaxProcs = Max([PID])
From [#ProcsToRun];
Declare #SQL Varchar(Max)
, #SchemaName sysname
, #ProcName sysname;
--run through each procedure, not caring if the count changes and only updating if there have been more than 23 hours since the last run
While #CurrentProc <= #MaxProcs
Begin
Select #SchemaName = [SchemaName]
, #ProcName = [ProcName]
From [#ProcsToRun]
Where [PID] = #CurrentProc;
Select #SQL = #SchemaName + '.' + #ProcName
+ ' #PrevCheck = 0,#HoursBetweenUpdates = '
+ Cast(#HoursBetweenEachRun As Varchar(5));
Exec (#SQL);
Set #CurrentProc = #CurrentProc + 1;
End;
End;
Go
However, the environment this is running in occasionally suffers from communications errors, with the query being cancelled whilst it is still executing.
My question is - can I wrap the entire procedure with a transaction statement and if I can what would happen in the event of the query being terminated early?
BEGIN Tran Test
Exec [Process].[UspLoad_LoadController] #HoursBetweenEachRun = 1;
COMMIT TRANSACTION Test
What I want to happen would be for the transaction to be rolled back - would this cater for this?
Yes it works,but you might have to see how many stored procs you have and impact of rollback.Normally you can use Set XACT_ABORT ON inside stored proc,but due to dynamic SQL,it wont have any effect..
Sample demo on how to wrap your proc
begin try
begin tran
exec usp_main
commit
end try
begin catch
rollback
end catch
some tests i did on trying to use XACT_ABORT with out any success.but wrapping your main proc in a tran and rolling back when any error occurs,rollback all stored procs too.
create table test2
(
id int)
create table test3
(
id int)
create proc usp_test2
as
begin
insert into test2
select 1
end
alter proc usp_test3
as
begin
insert into test3
select 1/0
end
alter proc usp_main
as
begin
set xact_abort on
declare #sql1 nvarchar(2000)
set #sql1='exec usp_test2'
declare #sql2 nvarchar(2000)
set #sql2='exec usp_test3'
exec (#sql1)
exec(#sql2)
end

removing all the characters except numbers

Could you please help me rewrite the following CP so when it reads from the file to remove any other characters except numbers:
what it does is read a file for example block.txt and addes each line into the table.
USE [db_Test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Cp_ImportBlackList]
AS
BEGIN
BEGIN TRY
BEGIN TRANSACTION Acbc
DECLARE #command nvarchar(max)
DECLARE #delcommand varchar(200)
DECLARE #txtfile nvarchar(200)
DECLARE #line nvarchar(2)
DECLARE #andreas nvarchar(200)
set #line='\n'
DECLARE #isExists INT
DECLARE #tempcol int
DECLARE MyCursor cursor fast_forward for
Select Users_ID from Prj_Users
open MyCursor
fetch next from MyCursor
into #tempcol
while ##fetch_status = 0
begin
set #txtfile = 'c:\BlackList\ ' + LTRIM(RTRIM(str(#tempcol))) + '.txt'
exec master.dbo.xp_fileexist #txtfile,
#isExists OUTPUT
if (#isExists =1)
begin
BEGIN TRY
BEGIN TRANSACTION ad
set #command=' BULK INSERT Prj_TempBlackList FROM ''' + #txtfile + ''''
set #command += ' WITH( ROWTERMINATOR = '''+ #line +''' )'
print #command
EXECUTE(#command)
delete Prj_TempBlackList where Tell in(select [BLList_TEll] from prj_BlackList where [BLList_UserID] = #tempcol)
insert into prj_BlackList select DISTINCT Tell,#tempcol from Prj_TempBlackList where Tell not in(select [BLList_TEll] from prj_BlackList where [BLList_UserID] = #tempcol)
delete from Prj_TempBlackList
set #delcommand ='del ' + #txtfile
exec xp_cmdshell #delcommand
print 'end'
COMMIT TRANSACTION ad
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION ad
SELECT ERROR_Message() AS ErrorNumber;
END CATCH
end
else
print 'no'
fetch next from MyCursor
into #tempcol
end
close MyCursor
deallocate MyCursor
set #txtfile = 'c:\BlackList\block.txt'
exec master.dbo.xp_fileexist #txtfile,
#isExists OUTPUT
if (#isExists =1)
begin
BEGIN TRY
BEGIN TRANSACTION ada
set #command=' BULK INSERT Prj_TempBlackList FROM ''' + #txtfile + ''''
set #command += ' WITH( ROWTERMINATOR = '''+#line+''' )'
EXECUTE(#command)
delete Prj_TempBlackList where Tell in(
select [BLList_TEll] from prj_BlackList where [BLList_UserID] is null)
insert into prj_BlackList SELECT DISTINCT Tell,null from
Prj_TempBlackList where Tell not in(
select [BLList_TEll] from prj_BlackList where [BLList_UserID] is null)
delete from Prj_TempBlackList
set #delcommand ='del ' + #txtfile
exec xp_cmdshell #delcommand
print 'yes'
COMMIT TRANSACTION ada
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION ada
SELECT ERROR_Message() AS ErrorNumber;
END CATCH
end
COMMIT TRANSACTION Acbc
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION Acbc
END CATCH
END
Try to avoid CURSORs and LOOPs!
This approach does it on the fly, but you really should think about if TSQL is the right tool...
DECLARE #tbl TABLE(ID INT IDENTITY, EvilString NVARCHAR(100));
INSERT INTO #tbl(EvilString) VALUES('ab23cd56jkl'),(' adfhasd l h45 hagf 78 l 9');
WITH RunningNumbers AS
(
SELECT ROW_NUMBER() OVER(ORDER BY A) AS Nmbr
FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS tblA(A)
,(VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS tblB(B)
,(VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS tblC(C)
,(VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS tblD(D)
,(VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS tblE(E)
,(VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS tblF(F)
)
,SingleChars AS
(
SELECT tbl.ID,rn.Nmbr,SUBSTRING(tbl.EvilString,rn.Nmbr,1) AS Chr
FROM #tbl AS tbl
CROSS APPLY (SELECT TOP(LEN(tbl.EvilString)) Nmbr FROM RunningNumbers) AS rn
)
SELECT ID,EvilString
,(
SELECT '' + Chr
FROM SingleChars AS sc
WHERE sc.ID=tbl.ID AND ASCII(Chr) BETWEEN 48 AND 57
ORDER BY sc.Nmbr
FOR XML PATH('')
) AS GoodString
FROM #tbl As tbl
The result
ID EvilString GoodString
1 ab23cd56jkl 2356
2 adfhasd l h45 hagf 78 l 9 45789

SQL procedure executes first line then stops

I am running an SQL procedure that has to update a certain table. When I run the procedure it says successfully completed, yet the records are not updated when I try to debug it, it run only the line SET ANSI ON, then it gives the successful message. I am using SQL server 2012
Am I missing something, is there anything I need to add? See my code here:
USE [CADDe_ProdCopy]
GO
/****** Object: StoredProcedure [dbo].[sp_sms_X203] Script Date: 2015/09/03 08:28:15 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[sp_sms_X203]
as
declare #lCount int
set #lCount = (select count(*) from tbl_X203_SMS where SMSSent = 0 )
if #lCount > 0
begin
DECLARE #cSMSeMail varchar(100)
declare #cSMSType varchar(10)
declare #cSMSSent int
declare #cRA varchar(10)
declare #cWizard varchar(7)
declare #cCName varchar(26)
declare #cContact varchar(30)
declare #cUsed_KM int
declare #cAmount_Due decimal(18, 2)
declare #cSMSMessage varchar(160)
declare #cvblf varchar(1)
declare #cCheckInDt datetime
declare #cCheckOutDt datetime
declare #err int
set #cvblf = '|'
declare lcursor CURSOR FOR
Select SMSType, RA, CName, Contact, Used_KM, Amount_Due, eMail, [CheckInDateTime] ,[CheckOutDateTime]
From tbl_X203_SMS WHERE SMSSent = 0
open lcursor
fetch next from lcursor into #cSMSType, #cRA, #cCName, #cContact, #cUsed_KM, #cAmount_Due, #cSMSeMail, #cCheckInDt, #cCheckOutDt
while ##FETCH_STATUS = 0
begin
--SET #cContact = '+27834115771'
--SET #cSMSeMail = 'amangelsdorf#avis.co.za'
-- Check that the date of the checkin is within same day
if rtrim(ltrim(#cSMSType)) = 'CheckIn'
begin
if datediff(day,#cCheckInDt,getdate()) = 0
begin
SET #cSMSMessage = left('Thank you '+ #cCName +' for renting with AVIS.',160)
SET #cSMSMessage = left( #cSMSMessage + ' RA#' + #cRA + 'Retrieve your invoice at http://www.avis.co.za/inv' ,160)
--if #cAmount_Due > 0
-- SET #cSMSMessage = left( #cSMSMessage + #cvbLf + 'AMT:R ' + cast(#cAmount_Due as varchar),160)
exec sp_sms_xml_post #cContact, #cSMSMessage, #cSMSeMail
end
end
-- Check that the date of the checkout is within same day
if rtrim(ltrim(#cSMSType)) = 'CheckOut'
begin
if datediff(day,#cCheckOutDt,getdate()) = 0
begin
--SET #cSMSMessage = left( 'Thank you for choosing AVIS.' + #cvbLf + 'For any assistance contact the AVIS Careline on Tel: 0800001669' ,160)
SET #cSMSMessage = left( 'Thank you for choosing AVIS. ' + #cvbLf + 'Kindly contact 0800001669 for any roadside or emergency assistance.' ,160)
exec sp_sms_xml_post #cContact, #cSMSMessage, #cSMSeMail
end
end
set #err = ##error
if #err = 0
begin
--print 'no error'
update tbl_X203_SMS set SMSSent = 1 where SMSType = #cSMSType and RA = #cRA
end
fetch next from lcursor into #cSMSType, #cRA, #cCName, #cContact, #cUsed_KM, #cAmount_Due, #cSMSeMail, #cCheckInDt, #cCheckOutDt
end
close lcursor
deallocate lcursor
end
`
You check your count value in
set #lCount = (select count(*) from tbl_X203_SMS where SMSSent = 0 )
if #lCount > 0
because may be you are getting value as 0 so it is not going inside the if condition, you can use print(#lCount ) before if and execute stored procedure from sql server.
The code that you have shown is the code to create / alter a stored procedure and won't execute it, hence the Successfully Compiled response.
In order to execute this procedure you will need to use the exec statement:
exec [dbo].[sp_sms_X203]

using ##ROWCOUNT in Dynamic SQL

I am using Dynamic SQL to retrieve datasets from multiple tables in order to monitor our daily data extraction from the iSeries system.
I have the below dynamic SQL code which works fine, but I want to only run the data to get each tables records if data has been extracted for the day
-- Create a table variable to store user data
DECLARE #myTable TABLE
(
docID INT IDENTITY(1,1),
docRef VARCHAR(50),
letterDir VARCHAR(500)
);
insert #myTable select docRef, saveDir from alpsMaster.dbo.uConfigData
-- Get the number of rows in the looping table
DECLARE #RowCount INT, #SQL nvarchar(500), #LoopSQL nvarchar(2000), #Date varchar(20)
set #Date='29 Oct 2013'
SET #RowCount = (SELECT COUNT(docID) FROM #myTable)
-- Declare an iterator
DECLARE #I INT
-- Initialize the iterator
SET #I = 1
-- Loop through the rows of a table #myTable
WHILE (#I <= #RowCount)
BEGIN
-- Declare variables to hold the data which we get after looping each record
DECLARE #docRef VARCHAR(10), #saveDir VARCHAR(500)
-- Get the data from table and set to variables
SELECT #docRef = docref FROM #myTable WHERE docID = #I
SELECT #saveDir = letterDir FROM #myTable WHERE docID = #I
-- Display the looped data
--PRINT 'Row No = ' + CONVERT(VARCHAR(2), #I) + '; docRef = ' + #docRef
select #LoopSQL='
use alpsProduction;
declare #SQL nvarchar(500);
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(''[dbo].['+#docRef+']''))
begin
if exists(select * from sys.columns
where Name = ''YPTMPID'' and Object_ID = OBJECT_ID(''[dbo].['+#docRef+']''))
begin
set #SQL=''SELECT t.template_name,'''''+#saveDir+''''', Y.*
FROM [alpsProduction].[dbo].'+#docRef+' Y, alpsMaster.dbo.uDocumentTemplates t
where DTEINP='''''+#Date+''''' and t.template_Id=y.YPTMPID and t.docRef='''''+#docRef+'''''''
exec sp_executesql #SQL
end
end
'
--print #LoopSQL
exec sp_executesql #LoopSQL
-- Increment the iterator
SET #I = #I + 1
END
so I tried using
IF ##ROWCOUNT >0
Begin
exec sp_executesql #SQL
end
but it seems to never populate the ##Rowcount.
Whats the best way to only run that statement (exec sp_executesql #SQL) if the current table (identified by #docRef) has records in it for todays date (in the format dd mmm yyyy)
Create job to execute a sql script in which u must check inserted data on current day then execute your sp. like this.
IF EXISTS ( SELECT * FROM #TABLE T WHERE DATEDIFF(DD, GETUTCDATE(), T.CREATEDON) = 0 )
BEGIN
EXEC SP_EXECUTESQL #SQL
END

Resources