Tuning Stored Procedure - sql-server

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)

Related

While executing the stored procedure from backend(MSSQL 2012).Unable to open a few modules from pb12.5 desktop application

We have an stored procedure to transfer the data(contract data) from database 1 to database 2(interfacing with SAP to Intermeidate Database , then our database), and this contain loops and more that one table in the execution.And we have an PB12.5 desktop application with several modules like procurement,crewing, employee etc.The issue is here while executing the stored procedure from MSSQL using exec, it will take nearly 2 minutes depend on the recieved data from SAP.During the execution I'm unable to open procurement window and it is opening once the stored procedure completed the execution.The other side employee window is opening without any issue.The below are my findings/comments
Procurement module is using table1 and table2 , but in the stored procedure we are not using any of this tables.We are using table 3 and table 4(but later we will use the table from procurement module in proc)
2.While executing the proc Im able to select the tables from procurement module using select * from table1.
3.None of the table is locking from proc.
4.We have tried the same scenarios from different PC same issue exist.
5.Later we will extend the stored procedure with more tables and multiple loops(cursor)
Below are the small part of procedure(we have to extend more and it is hold now because of this issue)
Many thanks in advance.
alter PROC [spectwosuite].[CST_GENERATE_IPurchase_contract]
as begin
SET NOCOUNT ON;
/**/
--truncate table spectwosuite.CUSTOM_SAP_CONTRACT_ITEM;
--truncate table spectwosuite.CUSTOM_SAP_CONTRACT_header;
--truncate table spectwosuite.CUSTOM_SAP_PROC_LOG;
--Variable declaration
DECLARE #MATERIALNO VARCHAR(20);
DECLARE #PURCHASEDOCNO VARCHAR(20);
DECLARE #PORTID NUMERIC(15);
DECLARE #PRICE DECIMAL(11,2);
DECLARE #PKID NUMERIC(16);
DECLARE #STOCKTYPEID NUMERIC(15);
DECLARE #STOCKTYPECODE VARCHAR(50);
DECLARE #STNAME VARCHAR(50);
DECLARE #UNITID NUMERIC(15);
DECLARE #BUSFLOWID NUMERIC(15);
DECLARE #BUSSTATUSID NUMERIC(15);
DECLARE #ITEMNO VARCHAR(5);
DECLARE #SUBITEMNO VARCHAR(10);
DECLARE #STOCKDISID NUMERIC(15);
DECLARE #PURCONTRACTID NUMERIC(15);
DECLARE #REVISIONNO NUMERIC(15);
DECLARE #DESCR NVARCHAR(100);
DECLARE #ADDRESSID NUMERIC(15);
DECLARE #DELTERMSID NUMERIC(15);
DECLARE #PAYTERMSID NUMERIC(15);
DECLARE #VALIDSTART DATETIME;
DECLARE #VALIDEND DATETIME;
DECLARE #CURRENCY NCHAR(3);
DECLARE #PRODUCTGROUPID NUMERIC(15);
DECLARE #PURCONTRACTPRODUCTGROUPID NUMERIC(15);
DECLARE #MATERIALGRP NVARCHAR(20);
DECLARE #NETPRICE NUMERIC(16,6);
DECLARE #BASEPRICE NUMERIC(16,6);
DECLARE #PRODUCTGROUPLINEID NUMERIC(15);
DECLARE #SECTION VARCHAR(20);
DECLARE #PUREXIST NUMERIC(1);
DECLARE #HEADERPKID NUMERIC(16);
DECLARE #ITEMPRICE NUMERIC(16,6);
DECLARE #BASEITEMPRICE NUMERIC(16,2);
DECLARE #PURCONTRACTVARIABLEID NUMERIC(15);
DECLARE #FACTORVALUE NUMERIC(9,4);
DECLARE #ITEMPERCENTAGE NUMERIC(15,2);
DECLARE #ITEMPRICEDIFF1 NUMERIC(15,2);
DECLARE #ITEMPRICEDIFF2 NUMERIC(15,2);
DECLARE #ITEMPKID NUMERIC(16);
/*CONT1: Transfering all the portid and purchase document number to different table */
--PRINT 'CONT1 START'
--PRINT GETDATE();
BEGIN TRY
--BEGIN TRANSACTION
--BEGIN
SET #SECTION='CONT1';
BEGIN TRANSACTION CONT1
INSERT INTO SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_PORT
(PORTID
,PURCHASE_DOC_NO
)
SELECT DISTINCT PORTID,PURCHASE_DOC_NO FROM SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_ITEM WITH(NOLOCK) WHERE IMPORT_STATUS IS NULL and DELETION_IND NOT IN('L','1')
and portid>0 and MATERIAL_NO<>'' and FACTOR>0 and
not exists (select PORTID from SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_PORT where PORTID=SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_PORT.PORTID
and PURCHASE_DOC_NO =SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_PORT.PURCHASE_DOC_NO) ORDER BY PURCHASE_DOC_NO,PORTID ASC;
COMMIT TRANSACTION CONT1
--END
----INSERT INTO spectwosuite.CUSTOM_SAP_PROC_LOG
---- (STATUS
---- ,DESCRIPTION
---- ,PROCESSEDDATE
---- ,RECORDCOUNT)
---- VALUES
---- (1,
---- 'CONT1'
---- ,GETDATE()
---- ,##ROWCOUNT
---- );
--PRINT 'CONT1 END'
--PRINT GETDATE();
/* CONT1 END */
/*CONT2 Inserting new item which one dont have price in all ports*/
/*Variable declaration*/
--PRINT 'CONT2 START'
--PRINT GETDATE();
-- BEGIN
SET #SECTION='CONT2';
--SELECT DISTINCT CAST(MATERIAL_NO AS VARCHAR(20))AS MATERIAL_NO,PURCHASE_DOC_NO FROM SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_ITEM WITH(NOLOCK) WHERE PURCHASE_DOC_NO='4600000820' and IMPORT_STATUS IS NULL and MATERIAL_NO<>'' and DELETION_IND NOT IN('L','1') and len(material_no)>0 and factor>0 and portid>0 ORDER BY MATERIAL_NO,PURCHASE_DOC_NO ASC;
DECLARE CONT2CR CURSOR FOR
SELECT DISTINCT CAST(MATERIAL_NO AS VARCHAR(20))AS MATERIAL_NO,PURCHASE_DOC_NO FROM SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_ITEM WITH(NOLOCK) WHERE IMPORT_STATUS IS NULL and MATERIAL_NO<>'' and DELETION_IND NOT IN('L','1') and len(material_no)>0 and factor>0 and portid>0 ORDER BY MATERIAL_NO,PURCHASE_DOC_NO ASC;
OPEN CONT2CR
FETCH NEXT FROM CONT2CR INTO #MATERIALNO,#PURCHASEDOCNO
WHILE ##FETCH_STATUS=0
BEGIN
BEGIN TRAN CONT2
select #PKID=MIN(pk_id),#PRICE=MIN(NET_PRICE) from SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_ITEM WITH(NOLOCK) WHERE MATERIAL_NO=#MATERIALNO AND PURCHASE_DOC_NO=#PURCHASEDOCNO and IMPORT_STATUS IS NULL and DELETION_IND NOT IN('L','1') and factor>0 and portid>0;
/*Retreiving port details table*/
DECLARE CONT2PORTCR CURSOR FOR
SELECT DISTINCT portid FROM SAP_INTERFACE.spectwosuite.custom_sap_contract_port WITH(NOLOCK) WHERE (SAP_INTERFACE.spectwosuite.custom_sap_contract_port.purchase_doc_no = #PURCHASEDOCNO) and ( custom_sap_contract_port.portid > 0 ) ;
OPEN CONT2PORTCR
FETCH NEXT FROM CONT2PORTCR INTO #PORTID
WHILE #PORTID>0
BEGIN
IF #PORTID>0
BEGIN
BEGIN TRAN
/*Insert Script*/
SET #SECTION='ITEM_ADDITION';
IF (select COUNT(*) from SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_ITEM WITH(NOLOCK) where MATERIAL_NO=CAST(#MATERIALNO AS varchar(20)) AND PORTID=#PORTID and PURCHASE_DOC_NO=#PURCHASEDOCNO and IMPORT_STATUS IS NULL and DELETION_IND NOT IN('L','1') and factor>0 and portid>0)<=0
BEGIN
INSERT INTO SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_ITEM
(DELETION_IND,PURCHASE_DOC_NO,ITEM_NO,MATERIAL_NO,SHORT_TEXT,MATERIAL_GRP,QTY,UOM,NET_PRICE,PORTID,TEMPPORTID,FACTOR)
select DELETION_IND,PURCHASE_DOC_NO,ITEM_NO,MATERIAL_NO,SHORT_TEXT,MATERIAL_GRP,QTY,UOM,NET_PRICE,#PORTID,1252,FACTOR from SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_ITEM WITH(NOLOCK) WHERE pk_id=#PKID and DELETION_IND<>'1' and IMPORT_STATUS IS NULL;
END
SET #PORTID=0;
COMMIT TRAN
END
FETCH NEXT FROM CONT2PORTCR INTO #PORTID
END
CLOSE CONT2PORTCR
DEALLOCATE CONT2PORTCR
COMMIT TRAN CONT2
FETCH NEXT FROM CONT2CR INTO #MATERIALNO,#PURCHASEDOCNO
END
CLOSE CONT2CR
DEALLOCATE CONT2CR
--END
--INSERT INTO spectwosuite.CUSTOM_SAP_PROC_LOG
-- (STATUS
-- ,DESCRIPTION
-- ,PROCESSEDDATE
-- ,RECORDCOUNT)
-- VALUES
-- (1,
-- 'CONT2'
-- ,GETDATE()
-- ,##ROWCOUNT
-- );
--PRINT 'CONT2 END'
--PRINT GETDATE();
/*CONT2 END*/
/*CONT3*/
--PRINT 'CONT3 START'
--PRINT GETDATE();
SET #SECTION='CONT3';
BEGIN TRAN CONT3
INSERT INTO spectwosuite.CUSTOM_SAP_CONTRACT_HEADER
(TABLEPKID
,PURCHASE_DOC_NO
,COMPANY_CODE
,CREATED_ON_DATE
,VENDOR_CODE
,PAYMENT_TERMS
,PURCHASE_GRP
,VALIDITY_START
,VALIDITY_END
,YOUR_REFERENCE
,OUR_REFERNCE
,TARGET_AMOUNT
,CURRENCY
,DESCRIPTION
,SHIPCODE
,STATUS
,CREATEDATE
,VALIDATESTART
,VALIDATEEND
,INTERNAL_STATUS
,INTERNAL_MESSAGE
)
SELECT
PK_ID
,PURCHASE_DOC_NO
,COMPANY_CODE
,CREATED_ON_DATE
,VENDOR_CODE
,PAYMENT_TERMS
,PURCHASE_GRP
,VALIDITY_START
,VALIDITY_END
,YOUR_REFERENCE
,OUR_REFERNCE
,TARGET_AMOUNT
,CURRENCY
,DESCRIPTION
,SHIPCODE
,STATUS
,CREATEDATE
,VALIDATESTART
,VALIDATEEND
,INTERNAL_STATUS
,INTERNAL_MESSAGE
FROM SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_HEADER WITH(NOLOCK)
where import_status is null and purchase_doc_no<>'' and validity_start<>'' and validity_end<>'' and currency<>''and status>0
and not exists(select pk_id from spectwosuite.CUSTOM_SAP_CONTRACT_HEADER WHERE TABLEPKID= SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_HEADER.PK_ID)
COMMIT TRAN CONT3
--INSERT INTO spectwosuite.CUSTOM_SAP_PROC_LOG
-- (STATUS
-- ,DESCRIPTION
-- ,PROCESSEDDATE
-- ,RECORDCOUNT)
-- VALUES
-- (1,
-- 'CONT3'
-- ,GETDATE()
-- ,##ROWCOUNT
-- );
--PRINT 'CONT3 END'
--PRINT GETDATE();
/*CONT3 END*/
/*CONT4*/
--PRINT 'CONT4 START'
--PRINT GETDATE();
SET #SECTION='CONT4';
BEGIN TRAN CONT4
INSERT INTO spectwosuite.CUSTOM_SAP_CONTRACT_ITEM
(TABLEPKID,PURCHASE_DOC_NO
,ITEM_NO
,DELETION_IND
,MATERIAL_NO
,SHORT_TEXT
,MATERIAL_GRP
,QTY
,UOM
,NET_PRICE
,PORTID
,STOCKTYPEID
,INTERNAL_MESSAGE
,INTERNAL_STATUS
,CONTRACTTYPE
,AGREEMENTSUBITEMNO
,FACTOR
)
select PK_ID,PURCHASE_DOC_NO
,ITEM_NO
,DELETION_IND
,MATERIAL_NO
,SHORT_TEXT
,MATERIAL_GRP
,QTY
,UOM
,NET_PRICE
,PORTID
,STOCKTYPEID
,INTERNAL_MESSAGE
,INTERNAL_STATUS
,CONTRACTTYPE
,AGREEMENTSUBITEMNO
,FACTOR
from SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_ITEM WITH(NOLOCK)
where IMPORT_STATUS is null and MATERIAL_NO<>'' and DELETION_IND<>'L' AND PORTID>0 and FACTOR>0 and LEN(SHORT_TEXT)>0 AND LEN(PURCHASE_DOC_NO)>0 AND
not exists (select PK_ID from spectwosuite.CUSTOM_SAP_CONTRACT_ITEM where TABLEPKID= SAP_INTERFACE.spectwosuite.CUSTOM_SAP_CONTRACT_ITEM.PK_ID ) ORDER BY PK_ID ASC;
COMMIT TRAN CONT4
-- /*Inserting History*/
-- /*Transfering process status to interface table.*/
TRUNCATE TABLE spectwosuite.CUSTOM_SAP_CONTRACT_HEADER;
TRUNCATE TABLE spectwosuite.CUSTOM_SAP_CONTRACT_ITEM;
DELETE FROM spectwosuite.CUSTOM_SAP_PROC_LOG WHERE STATUS=99;
COMMIT
-- /*PURCHASE CONTRACT CREATION END*/
-- SET NOCOUNT OFF;
-- --COMMIT TRANSACTION
END TRY
BEGIN CATCH
DECLARE #ERRORNUMBER VARCHAR(20);
DECLARE #ERRMSG VARCHAR(MAX);
SET #ERRORNUMBER=CAST(ERROR_LINE() AS VARCHAR(20));
SET #ERRMSG=ERROR_MESSAGE();
BEGIN TRAN ER
INSERT INTO spectwosuite.CUSTOM_SAP_PROC_LOG
(STATUS
,DESCRIPTION
,PROCESSEDDATE
,RECORDCOUNT
,ERRORMSG)
VALUES
(
88,
#SECTION
,getdate()
,1
,#ERRORNUMBER +','+ #ERRMSG
);
COMMIT TRAN ER
END CATCH
END
Try to add Begin tran and commit Tran without success

Incorrect syntax near GOTO label in SQL Server stored procedure

I am using a GOTO statement inside a try block and also in catch block in a stored procedure.When it comes to the definition of GOTO label after END catch, it shows incorrect syntax error. below is the procedure. Error comes at 'AuditLog :' in the procedure. please help me with this.
ALTER PROCEDURE [dbo].[Proc_PIP_Employee]
#Flag int = 1,
#Empid int = 0,
#Name nvarchar(500) = '',
#Designation nvarchar(200) = '',
#Department nvarchar(200) = '',
#DateofJoin datetime = '' ,
#Phone nvarchar(3000) = '',
#Isactive int = 1,
#LoginUser nvarchar(500) = ''
AS
BEGIN
SET NOCOUNT ON ;
DECLARE #r int;
BEGIN TRY
BEGIN TRANSACTION
DECLARE #errorMessage VarChar(8000),
#errorSeverity Int,
#errorState Int,
#ReturnId Int,
#AlCode varchar(50),
#AlDesc varchar(1000),
#AlOp varchar(50),
#AlStatus varchar(50)
IF (#Flag = 1)
BEGIN
IF EXISTS (SELECT 1 FROM dbo.PIP_Employee
GROUP BY Name, Phone
HAVING COUNT(ID) > 0
AND Name = #Name AND Phone = #Phone)
BEGIN
SET #ReturnId = 0
SET #AlCode = 'ERROR_1001'
SET #AlDesc = CONCAT('Add Record of ',#Name,' failed due to duplicate entry')
SET #AlOp = 'ADD'
SET #AlStatus = 'ERROR'
GOTO AuditLog
END
ELSE
BEGIN
INSERT INTO dbo.PIP_Employee (Name, Designation, Department, DateofJoin, Phone, IsPresent)
VALUES (#Name, #Designation, #Department, #DateofJoin, #Phone, #Isactive)
SET #ReturnId = 1
END
END
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SET #AlCode = ERROR_SEVERITY()
SET #AlDesc = ERROR_MESSAGE()
SET #AlOp = 'SQL TRANSACTION FAILURE'
SET #AlStatus = ERROR_STATE();
GOTO AuditLog
IF (##trancount > 0)
ROLLBACK TRANSACTION
END CATCH
AuditLog :
INSERT INTO dbo.PIP_AuditLog (Aud_Code, Aud_Desc, Aud_Operation, Aud_Status, Aud_Createddate, Aud_ActionBy)
VALUES (#AlCode, #AlDesc, #AlOp, #AlStatus, GETDATE(), #LoginUser)
SET NOCOUNT OFF
END
AuditLog : seems to be an incorrect syntax.
If you are not using an IDE with syntax checking like SQL Server Management Studio, you might want to check out some free tools like https://ubitsoft.com/t-sql-beautilyzer/.
This indicates that line 68 is bad. Namely that labels should NOT have a space between the label and the ':'

Will all transaction in this stored procedure be rolled back

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?

The conversion of the varchar value overflowed an int column while REPLACE

I have table with a myNumber varchar(50) column which stores values with lead zero, like a '0000001111'.
Now I want to replace leading '0000' with '12', like '12001111'.
I tried this statement:
UPDATE myDB.dbo.myTable
SET myNumber = REPLACE(myNumber, '0000', '12')
WHERE myNumber LIKE '0000%'
But this caused an error:
Msg 248, Level 16, State 1, Procedure trplist_for_Inserted_Updated_Deleted Line 80
The conversion of the varchar value "831116399075' overflowed an int column.
Why this error caused if all columns are the varchar?
What should I do?
UPDATED
Sorry guys, the reason of error it is the tables trigger.
Here is triggers logic
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
ALTER TRIGGER [dbo].[trplist_for_Inserted_Updated_Deleted]
ON [dbo].[pList]
FOR Insert, Update, Delete
NOT FOR REPLICATION
AS
SET NOCOUNT ON
Declare #Result_check Int
Declare #NameTable nvarchar(30)
set #NameTable='plist'
Declare #FieldName nvarchar(30)
set #FieldName='ChangeTime'
Declare #Columns varbinary(MAX)
set #Columns=COLUMNS_UPDATED()
Execute CheckChangeFields #Columns, #NameTable, #FieldName, #Result_check
if #Result_check = 1
begin
return
end
set #FieldName='DateTimeInArchive'
Execute CheckChangeFields #Columns, #NameTable, #FieldName, #Result_check
if #Result_check = 1
begin
return
end
Declare #stateRecord Int
IF EXISTS(SELECT * FROM inserted)
IF EXISTS(SELECT * FROM deleted)
BEGIN
SET #stateRecord = 1 --Update
--PRINT 'Update'
END
ELSE
BEGIN
--PRINT 'Insert'
SET #stateRecord = 0 --Insert
END
ELSE
BEGIN
--PRINT 'Is DELETE'
IF EXISTS(SELECT * FROM deleted)
BEGIN
SET #stateRecord = 2 --Delete
--PRINT 'DELETE'
END
ELSE
BEGIN
SET #stateRecord = -1
--PRINT 'No DELETE'
END
END
IF #stateRecord = -1
RETURN
declare #id_value int
Declare #status_record int
declare #inn int
declare #Company int
declare #tabnumber varchar(50)
if (#stateRecord in (0,1))
BEGIN
--inserted or updated
--проверка на изменение поля StatusRecord
declare #Result_check_status_record int
if Exists(select * from Deleted where checksum(StatusRecord) In (select Checksum(StatusRecord) from Inserted))
select #Result_check_status_record= 1--одинаковые
else
select #Result_check_status_record= 0--разные
DECLARE cursor_inserted_trpList_Inserted_Updated_Delete_logs CURSOR LOCAL FOR select id, StatusRecord, INN, TabNumber, Company from inserted
OPEN cursor_inserted_trpList_Inserted_Updated_Delete_logs
FETCH NEXT FROM cursor_inserted_trpList_Inserted_Updated_Delete_logs INTO #id_value, #status_record,#inn, #tabnumber, #Company
WHILE ##FETCH_STATUS = 0
BEGIN
if (#inn<>'')
begin
if Exists(select id from plist where (id<> #id_value) and (INN=#inn))
begin
RollBack
RAISERROR('Данный INN уже имеется в базе', 16,2)
CLOSE cursor_inserted_trpList_Inserted_Updated_Delete_logs
return
end
end
if (#tabnumber<>'') and (#tabnumber<>'0')
begin
if #Company = 0
begin
if Exists(select id from plist where (id<> #id_value) and (TabNumber=#tabnumber) and (Company<=0))
begin
RollBack
RAISERROR('Данный TabNumber уже имеется в базе', 16,2)
CLOSE cursor_inserted_trpList_Inserted_Updated_Delete_logs
return
end
end
else
begin
if Exists(select id from plist where (id<> #id_value) and (TabNumber=#tabnumber) and (Company=#Company))
begin
RollBack
RAISERROR('Данный TabNumber уже имеется в базе в данном подразделении', 16,2)
CLOSE cursor_inserted_trpList_Inserted_Updated_Delete_logs
return
end
end
end
if ((#status_record&1)>0)
begin
if (#Result_check_status_record=0)
begin
Execute GustIsRelease #id_value
update guest set IDNoFace=0 where PListID=#id_value
Declare #dmtm datetime
if Exists(select id from plist where (id=#id_value) and (IsNull(DateTimeInArchive, '')=''))
begin
Update plist set DateTimeInArchive=GetDate() where (id=#id_value) and (IsNull(DateTimeInArchive, '')='')
end
end
end
else
begin
if Exists(select id from plist where (id=#id_value) and (IsNull(DateTimeInArchive, 1)<>1))
Update plist set DateTimeInArchive=Null where (id=#id_value) and (IsNull(DateTimeInArchive, 1)<>1)
end
FETCH NEXT FROM cursor_inserted_trpList_Inserted_Updated_Delete_logs INTO #id_value, #status_record,#inn, #tabnumber, #Company
END
CLOSE cursor_inserted_trpList_Inserted_Updated_Delete_logs
END
if (#stateRecord=2)
BEGIN
DECLARE cursor_inserted_trpList_Inserted_Updated_Delete_logs CURSOR LOCAL FOR select id from deleted
OPEN cursor_inserted_trpList_Inserted_Updated_Delete_logs
FETCH NEXT FROM cursor_inserted_trpList_Inserted_Updated_Delete_logs INTO #id_value
WHILE ##FETCH_STATUS = 0
BEGIN
if Exists(select id from pmark where owner=#id_value)
begin
RollBack
RAISERROR('У сотрудника остались активные пароли', 16,2)
CLOSE cursor_inserted_trpList_Inserted_Updated_Delete_logs
return
end
if Exists(select id from guest where IDNoFace=#id_value)
begin
RollBack
RAISERROR('Сотрудник привязан к посетителю', 16,2)
CLOSE cursor_inserted_trpList_Inserted_Updated_Delete_logs
return
end
update guest set IDNoFace=0 where IDNoFace=#id_value
update guest set ReceiveListId=0 where ReceiveListId=#id_value
FETCH NEXT FROM cursor_inserted_trpList_Inserted_Updated_Delete_logs INTO #id_value
END
CLOSE cursor_inserted_trpList_Inserted_Updated_Delete_logs
END
You could use STUFF
UPDATE myDB.dbo.myTable
SET myNumber=stuff(myNumber, 1,4, '12')
WHERE myNumber LIKE '0000%'
Use can use SUBSTRING/STUFF as below:
SUBSTRING:
UPDATE #tblTest
SET Number='12'+SUBSTRING(Number,5,LEN(NUMBER))
WHERE LEFT(Number,4)='0000'
AND LEN(Number)>4
STUFF:
UPDATE #tblTest
SET Number=STUFF(Number, 1,4, '12')
WHERE LEFT(Number,4)='0000'
AND LEN(Number)>4
Use substring function to accomplish the result u want
UPDATE myDB.dbo.myTable
SET Number='12'+SUBSTRING(myNumber,5)
WHERE SUBSTRING(myNumber,1,4)='0000';

Check if record exists, if yes “update” if not “insert” using cursor sql server

I have this trigger that after insert update and insert data in a table, using the if as paramter for the insert or update, at the same time i have another trigger after update that changes another register. The problem is that the first trigger when does the update it trigger the update trigger... So occours that I had to protect the first trigger by checking if there´s a register there before the insert BUT I have a cursor to insert the data in the middle of all this, after I did checking the insert of one register occurs BUT the others inside the cursor aren´t inserted in the table just one register of the list in the cursor... I cannot find the problem, please help...
this is my trigger:
ALTER TRIGGER [dbo].[tr_inclusao_dupla] ON [dbo].[tb_patrimonio]
AFTER INSERT
AS
BEGIN
begin try
IF EXISTS (SELECT * FROM INSERTED) AND EXISTS (SELECT * FROM DELETED)
BEGIN
declare #id as int
declare #count as int
declare #qtd as int
declare #emlote as bit
declare #nr_serie as varchar(100)
declare #nr_patrimonio as varchar(100)
declare #dm_identificado as bit
declare #nr_inventario as varchar(100)
set #nr_patrimonio = (select nr_patrimonio_efetivo from inserted)
set #nr_serie = (select nr_serie from inserted)
set #nr_inventario = (select nr_inventario from inserted)
/*single insert*/
if (#nr_patrimonio is not null or #nr_serie is not null or #nr_inventario is not null)
begin
set #emlote =0
declare registros cursor for
select cd_patrimonio , nr_qtd_lote,nr_serie, nr_patrimonio_efetivo from inserted
open registros
fetch next from registros into #id, #qtd, #nr_serie, #nr_patrimonio
while( ##fetch_status = 0)
begin
set #dm_identificado = 1
update tb_patrimonio set dm_identificado = #dm_identificado, dm_em_lote = #emlote
where cd_patrimonio = #id
end
fetch next from registros into #id, #qtd,#nr_serie, #nr_patrimonio
close registros
deallocate registros
end
END
ELSE
BEGIN
/*multiple insert*/
begin
set #emlote =0
set #dm_identificado = 0
declare registros2 cursor for
select cd_patrimonio , nr_qtd_lote,nr_serie, nr_patrimonio_efetivo from inserted
open registros2
fetch next from registros2 into #id, #qtd, #nr_serie, #nr_patrimonio
while( ##fetch_status = 0)
begin
print #qtd
set #count = 1
update tb_patrimonio set dm_identificado = #dm_identificado, dm_em_lote = #emlote
where cd_patrimonio = #id
while (#count <= (#qtd-1))
begin
INSERT INTO [dbo].[tb_patrimonio]
([dm_patrimonio]
,[dm_em_lote]
,[nr_qtd_lote]
,[cd_grupo_produto]
,[nm_patrimonio]
,[nr_patrimonio_efetivo]
,[nr_patrimonio_antigo]
,[nr_serie]
,[ds_descricao]
,[nr_lacre]
,[cd_barra]
,[dm_tipo_entrada]
,[nr_garantia]
,[cd_nota_fiscal]
,[ds_garantia]
,[img_patrimonio]
,[cd_situacao_patrimonio]
,[cd_orgao]
,[cd_local]
,[dm_situacao]
,[cd_usuario_inc]
,[cd_estado_patrimonio]
,[cd_tipo_posse]
,[cd_usuario_alt]
,[dt_alteracao]
,[cd_usuario]
,[dt_inclusao]
,[cd_estado_equipamento]
,[cd_fornecedor]
,[nr_termo]
,[img_termo]
,[dm_identificado]
,[dt_instalacao_equipamento]
,[nr_inventario])
SELECT
[dm_patrimonio]
,#emlote
,[nr_qtd_lote]
,[cd_grupo_produto]
,[nm_patrimonio]
,[nr_patrimonio_efetivo]
,[nr_patrimonio_antigo]
,[nr_serie]
,[ds_descricao]
,[nr_lacre]
,[cd_barra]
,[dm_tipo_entrada]
,[nr_garantia]
,[cd_nota_fiscal]
,[ds_garantia]
,[img_patrimonio]
,[cd_situacao_patrimonio]
,[cd_orgao]
,[cd_local]
,[dm_situacao]
,[cd_usuario_inc]
,[cd_estado_patrimonio]
,[cd_tipo_posse]
,[cd_usuario_alt]
,[dt_alteracao]
,[cd_usuario]
,[dt_inclusao]
,[cd_estado_equipamento]
,[cd_fornecedor]
,[nr_termo]
,[img_termo]
,#dm_identificado
,[dt_instalacao_equipamento]
,[nr_inventario]
FROM inserted where cd_patrimonio = #id
set #count = #count + 1
end
fetch next from registros2 into #id, #qtd,#nr_serie, #nr_patrimonio
end
close registros2
deallocate registros2
end
END
end try
begin catch
declare #errormessage nvarchar(4000)
declare #errorseverity int
declare #errorstate int
select
#errormessage = ERROR_MESSAGE(),
#errorseverity = ERROR_SEVERITY(),
#errorstate = ERROR_STATE()
raiserror (
#errormessage,
#errorseverity,
#errorstate
)
end catch end

Resources