Im getting this error message I've tried to look at my code I cant seem to see where its coming from, please help.
ERROR:-
Msg 102, Level 15, State 1, Procedure _TESTbspPostAPTrans, Line 249
Incorrect syntax near '0'.
SET ANSI_NULLS ON
GO
CREATE procedure [dbo].[_TESTbspPostAPTrans]
#AutoIdx bigint = NULL OUTPUT,
#TxDate datetime,
#Id varchar(5),
#AccountLink int,
#TrCodeID int,
#Debit float,
#Credit float,
#CurrencyID int,
#ExchangeRate float,
#ForeignDebit float,
#ForeignCredit float,
#Description varchar(100),
#TaxTypeID int,
#Reference varchar(50),
#Order_No varchar(50),
#ExtOrderNum varchar(50),
#AuditNumber varchar(50),
#Tax_Amount float,
#ForeignTaxAmount float,
#Project int,
#Outstanding float,
#ForeignOutstanding float,
#InvNumKey bigint,
#UserName varchar(20),
#Reference2 varchar(50),
#SettlementTermsID int,
#TxBranchID int,
#GLTaxAccountID int = 0,
#cLineUserFields varchar (max) = ''
as
set nocount on
set identity_insert PostAP on
if (IsNull(#AccountLink, 0) = 0) begin
RAISERROR('_bspPostAPTrans: No Accounts Payable Account specified!', 16, 1)
return 0
end
else
if (IsNull(#Id, '') = '') begin
RAISERROR('_bspPostAPTrans: No Transaction ID specified!', 16, 1)
return 0
end
else
if (IsNull(#TrCodeID, 0) = 0) begin
RAISERROR('_bspPostAPTrans: No Transaction Code specified!', 16, 1)
return 0
end
else
if (IsNull(#AuditNumber, '') = '') begin
RAISERROR('_bspPostAPTrans: No Audit Trail Number specified!', 16, 1)
return 0
end
--begin tran --CC: Will now be controlled in Code
declare #SPError int
declare #BranchID int
select #BranchID = Vendor_iBranchID from Vendor where DCLink = #AccountLink
if isnull(#AutoIdx, 0) <= 0 begin
if isnull (#AccountLink, 0) = 4917 begin
set nocount on
set identity_insert PostAR on
--begin tran --CC: Will now be controlled in Code
select #BranchID = Client_iBranchID from Client where DCLink = #AccountLink
select #AutoIdx = ident_current('PostAR') + 1
insert into PostAR
(
AutoIdx,
TxDate,
[Id],
AccountLink,
TrCodeID,
Debit,
Credit,
iCurrencyID,
fExchangeRate,
fForeignDebit,
fForeignCredit,
[Description],
TaxTypeID,
Reference,
Order_No,
ExtOrderNum,
cAuditNumber,
Tax_Amount,
fForeignTax,
Project,
Outstanding,
fForeignOutstanding,
InvNumKey,
UserName,
cReference2,
iPostSettlementTermsID,
iTxBranchID,
iGLTaxAccountID
)
values
(
#AutoIdx,
#TxDate,
#Id,
#AccountLink,
#TrCodeID,
#Debit,
#Credit,
#CurrencyID,
#ExchangeRate,
#ForeignDebit,
#ForeignCredit,
#Description,
#TaxTypeID,
#Reference,
#Order_No,
#ExtOrderNum,
#AuditNumber,
#Tax_Amount,
#ForeignTaxAmount,
#Project,
#Outstanding,
#ForeignOutstanding,
#InvNumKey,
#UserName,
#Reference2,
#SettlementTermsID,
#TxBranchID,
#GLTaxAccountID
)
set #SPError = ##ERROR
set identity_insert PostAR off
-- Post User Defined Fields
if (len (#cLineUserFields) > 0) begin
declare #UDFSQLText1 varchar(max)
set #UDFSQLText1 = 'update PostAR set ' + #cLineUserFields + ' where AutoIdx = ' + CAST(#AutoIdx as varchar)
execute (#UDFSQLText1)
set #SPError = ##ERROR
if #SPError <> 0 goto AbortTran
-- Update Client Balances
end
UPDATE dbo.Client
SET DCBalance = Round(IsNull (DCBalance, 0) + (#Debit - #Credit), 4),
fForeignBalance = Round(IsNull(fForeignBalance, 0) + (#ForeignDebit - #ForeignCredit), 4)
WHERE DCLink = #AccountLink
set #SPError = ##ERROR
if #SPError <> 0 goto AbortTran1
goto CommitTran1
--rollback tran --CC: Will now be controlled in Code
RAISERROR (#SPError, 16, 1)
return #SPError
if #SPError <> 0 goto AbortTran
END
select #AutoIdx = ident_current('PostAP') + 1
insert into PostAP
(
AutoIdx,
TxDate,
[Id],
AccountLink,
TrCodeID,
Debit,
Credit,
iCurrencyID,
fExchangeRate,
fForeignDebit,
fForeignCredit,
[Description],
TaxTypeID,
Reference,
Order_No,
ExtOrderNum,
cAuditNumber,
Tax_Amount,
fForeignTax,
Project,
Outstanding,
fForeignOutstanding,
InvNumKey,
DTStamp,
UserName,
cReference2,
iPostSettlementTermsID,
PostAP_iBranchID,
iTxBranchID,
iGLTaxAccountID
)
values
(
#AutoIdx,
#TxDate,
#Id,
#AccountLink,
#TrCodeID,
#Debit,
#Credit,
#CurrencyID,
#ExchangeRate,
#ForeignDebit,
#ForeignCredit,
#Description,
#TaxTypeID,
#Reference,
#Order_No,
#ExtOrderNum,
#AuditNumber,
#Tax_Amount,
#ForeignTaxAmount,
#Project,
#Outstanding,
#ForeignOutstanding,
#InvNumKey,
GetDate(),
#UserName,
#Reference2,
#SettlementTermsID,
#BranchID,
#TxBranchID,
#GLTaxAccountID
)
set #SPError = ##ERROR
set identity_insert PostAP off
if #SPError <> 0 goto AbortTran1
-- Post User Defined Fields
if (len (#cLineUserFields) > 0) begin
declare #UDFSQLText varchar(max)
set #UDFSQLText = 'update PostAP set ' + #cLineUserFields + ' where AutoIdx = ' + CAST(#AutoIdx as varchar)
execute (#UDFSQLText)
set #SPError = ##ERROR
if #SPError <> 0 goto AbortTran1
end
-- Update Vendor Balances
UPDATE VENDOR
SET DCBalance = Round(IsNull (DCBalance, 0) + (#Credit - #Debit), 4),
fForeignBalance = Round(IsNull(fForeignBalance, 0) + (#ForeignCredit - #ForeignDebit), 4)
WHERE DCLink = #AccountLink
set #SPError = ##ERROR
if #SPError <> 0 goto AbortTran1
goto CommitTran1
AbortTran1:
--rollback tran --CC: Will now be controlled in Code
RAISERROR (#SPError, 16, 1)
return #SPError
CommitTran1:
--commit tran --CC: Will now be controlled in Code
return 0 --scope_identity() -- return can only return an int, not a bigint,
-- AutoIdx has been added as a paramater for the BA sync and is an OUTPUT paramter
GO
Any help will be greatly appreciated
I think in line 62 and 63 you have 2 opened BEGIN with just first END in line 159.on END is missing in line 160
Related
After Running this query, I am getting one custom Error :
Debit account balance can not be less than 0. somemail#7dmail.com/123/xxx/123456
And Two regular errors :
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 2, current count = 0.
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.
I think, that transaction errors happen because something is throwing exception before transaction is committed.
Custom Error is from another query(AddJournalEntry) which is written below. I can not see connection between these two queries.
Query:
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[RevokeOrder]
#OrderId int = null
--,#EntryId int OUTPUT
AS
declare #OrderTypeId nvarchar(30)
declare #MasterEntryId int
declare #NewEntryId int
declare #CustomerGuid uniqueidentifier
declare #Debit int
declare #Credit int
declare #Explanation nvarchar(100)
declare #Amount decimal(18, 8)
declare #AmountFilled decimal(18, 8)
declare #Total decimal(18, 8)
declare #TotalLeft decimal(18, 8)
declare #AmountLeft decimal(18, 8)
declare #AssetId nvarchar(30)
declare #QuoteAssetId nvarchar(30)
declare #QuotePrice decimal(18, 8)
declare #AssetReserveAccountId int
declare #AssetAccountId int
declare #EntryAmount decimal(18, 8)
BEGIN;
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET XACT_ABORT ON;
SET NOCOUNT ON;
print ''
print '++++++++++++++++++++++++++++++++++++++++++++++++'
print 'Start RevokeOrder procedure'
print '++++++++++++++++++++++++++++++++++++++++++++++++'
print ''
begin tran
select
#OrderTypeId = OrderTypeId,
#CustomerGuid = CustomerGuid,
#Amount = Amount,
#AmountFilled = AmountFilled,
#AssetId = AssetId,
#QuoteAssetId = QuoteAssetId,
#QuotePrice = QuotePrice,
#Total = Total,
#TotalLeft = TotalLeft
from dbo.[vOrder] WITH (HOLDLOCK, ROWLOCK)
where OrderId = #OrderId
if ##ERROR <> 0 or ##ROWCOUNT = 0
begin
rollback
raiserror ('Order not found', 16, 1)
return 3
end
set #AmountLeft = #Amount - ISNULL(#AmountFilled, 0)
if (#OrderTypeId = 'buy')
begin
--declare #Released decimal(18, 8)
--select #Released = coalesce(SUM(Total), 0)
--from dbo.[vOrder]
--where OrderId in (select FillerId from dbo.Filler where OrderId = #OrderId)
--or OrderId in (select OrderId from dbo.Filler where FillerId = #OrderId)
declare #Released decimal(18, 8)
select #Released = Amount
from dbo.Trade t join dbo.JournalEntry j on t.EntryId = j.EntryId
where SourceOrderId = #OrderId
set #Released = ISNULL(#Released, 0)
print 'Order Type = ' + #OrderTypeId
print '#InitialAmount = ' + isnull(cast (#Amount as nvarchar), 'NULL') + ' ' + #AssetId
print '#AmountFilled = ' + isnull(cast (#AmountFilled as nvarchar), 'NULL') + ' ' + #AssetId
print '#AmountLeft = ' + isnull(cast (#AmountLeft as nvarchar), 'NULL')
print ''
print '#InitialBlocked = ' + isnull(cast (#Total as nvarchar), 'NULL') + ' ' + #QuoteAssetId
print '#Released = ' + cast (#Released as nvarchar) + ' ' + #QuoteAssetId
print '#CurrentBlocked = ' + isnull(cast (#TotalLeft as nvarchar), 'NULL') + ' ' + #QuoteAssetId
print ''
set #Explanation = N'Revoke order process. Reverse blocked quote amount' --+ 'reverse' --+ cast(#EntryId as nvarchar)
DECLARE #RC int
declare #Date datetimeoffset
set #Date = sysdatetimeoffset()
set #AssetReserveAccountId = (select AccountId from dbo.Account where CustomerGuid = #CustomerGuid and MasterAccountNo = 99931 and AssetId = #QuoteAssetId)
set #AssetAccountId = (select AccountId from dbo.Account where CustomerGuid = #CustomerGuid and MasterAccountNo = 9993 and AssetId = #QuoteAssetId)
set #EntryAmount = #Amount * #QuotePrice - #Released
print 'Order total = ' + cast (#Amount * #QuotePrice as nvarchar)
print 'Money spent to buy asset = ' + cast (#Released as nvarchar)
print 'Money to refund to buyer = ' + cast (#EntryAmount as nvarchar)
print '#Amount = ' + cast (#Amount as nvarchar)
print '#QuotePrice = ' + cast (#QuotePrice as nvarchar)
--rollback
--return 111
EXECUTE #RC = [dbo].[AddJournalEntry]
#Date
,#AssetReserveAccountId
,#AssetAccountId
,#EntryAmount
,#QuoteAssetId
,#Explanation
,'revoke'
,#OrderId
,#MasterEntryId
,#NewEntryId OUTPUT
if ##ERROR <> 0 or #RC <> 0
begin
rollback
raiserror ('Revoke order process. Can not add reverse blocked quote amount journal entry', 16, 1)
return 4
end
end
if (#OrderTypeId = 'sell')
begin
print 'sell order'
set #Explanation = N'Revoke order process. Reverse blocked amount journal entry' --+ 'რევერსი' --+ cast(#EntryId as nvarchar)
set #Date = sysdatetimeoffset()
set #AssetReserveAccountId = (select AccountId from dbo.Account where CustomerGuid = #CustomerGuid and MasterAccountNo = 99931 and AssetId = #AssetId)
set #AssetAccountId = (select AccountId from dbo.Account where CustomerGuid = #CustomerGuid and MasterAccountNo = 9993 and AssetId = #AssetId)
set #EntryAmount = #AmountLeft
print '#EntryAmount = ' + isnull(cast (#EntryAmount as nvarchar), 'NULL')
EXECUTE #RC = [dbo].[AddJournalEntry]
#Date
,#AssetReserveAccountId
,#AssetAccountId
,#EntryAmount
,#AssetId
,#Explanation
,'revoke'
,#OrderId
,#MasterEntryId
,#NewEntryId OUTPUT
if ##ERROR <> 0 or #RC <> 0
begin
rollback
raiserror ('Revoke order process. Can not add reverse blocked amount journal entry', 16, 1)
return 5
end
end
-- STEP 4
update dbo.[Order]
set OrderStatusId = 30
where OrderId = #OrderId
if ##ERROR <> 0 or ##ROWCOUNT = 0
begin
rollback
raiserror ('Can not set order status to REVOKED', 16, 1)
return 2
end
commit tran
return 0
END
go
Custom error I am getting is defined in query called
AddJournalEntry
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE [dbo].[AddJournalEntry]
#Date datetimeoffset,
#Debit int,
#Credit int,
#Amount decimal(18, 8),
#AssetId nvarchar(50),
#Explanation nvarchar(100),
#EntryType nvarchar(50),
#OrderId int = null,
#MasterEntryId int = null,
#EntryId int OUTPUT
AS
declare #DebitBalance decimal(18, 8)
declare #DebitAccountAssetId nvarchar(10)
declare #CreditAccountAssetId nvarchar(10)
declare #CreditBalance decimal(18, 8)
declare #ToIncrease nvarchar(100)
declare #DebitAccountTitle nvarchar(500)
declare #CreditAccountTitle nvarchar(500)
declare #Error nvarchar(500)
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET XACT_ABORT ON;
SET NOCOUNT ON;
print ''
print '++++++++++++++++++++++++++++++++++++++++++++++++'
print 'Start AddJournalEntry procedure'
print '++++++++++++++++++++++++++++++++++++++++++++++++'
print ''
begin tran
-- STEP 1
print '#Debit = ' + isnull(cast(#Debit as nvarchar), 'NULL')
print '#Credit = ' + isnull(cast(#Credit as nvarchar), 'NULL')
print '#AssetId = ' + cast(#AssetId as nvarchar(50))
print '#Amount = ' + cast(#Amount as nvarchar(50))
update dbo.Account
set Debit = Debit + #Amount, LastTransactionDate = SYSDATETIMEOFFSET()
where AccountId = #Debit
if ##ERROR <> 0 or ##ROWCOUNT = 0
begin
rollback
raiserror ('Can not update debit account balance', 16, 1)
return 2
end
update dbo.Account
set Credit = Credit + #Amount, LastTransactionDate = SYSDATETIMEOFFSET()
where AccountId = #Credit
if ##ERROR <> 0 or ##ROWCOUNT = 0
begin
rollback
raiserror ('Can not find or update credit account balance', 16, 1)
return 3
end
select
#DebitBalance = Balance,
#ToIncrease = ToIncrease,
#DebitAccountTitle = AccountFullTitle
from dbo.vAccount
where AccountId = #Debit and AssetId = #AssetId
if ##ERROR <> 0 or ##ROWCOUNT = 0
begin
rollback
raiserror ('Can not find debit account', 16, 1)
return 4
end
print 'New Debit Balance = ' + cast(#DebitBalance as nvarchar(50))
if (#DebitBalance < 0 and #ToIncrease = 'debit') or (#DebitBalance > 0 and #ToIncrease = 'credit')
begin
rollback
set #Error = 'Debit account balance can not be less than 0. ' + #DebitAccountTitle
raiserror (#Error, 16, 1)
return 5
end
-- STEP 4
select
#CreditBalance = Balance,
#ToIncrease = ToIncrease,
#CreditAccountTitle = AccountFullTitle
from dbo.vAccount
where AccountId = #Credit and AssetId = #AssetId
if ##ERROR <> 0 or ##ROWCOUNT = 0
begin
rollback
raiserror ('Can not find credit account', 16, 1)
return 55
end
if (#CreditBalance > 0 and #ToIncrease = 'credit') or (#CreditBalance < 0 and #ToIncrease = 'debit')
begin
rollback
set #Error = 'Credit account balance can not be less than 0. ' + #CreditAccountTitle
raiserror ( #Error, 16, 1)
return 56
end
-- STEP 4
insert dbo.JournalEntry
select SYSDATETIMEOFFSET(), #Debit, #Credit, #Amount, #AssetId, #Explanation, #DebitBalance, #CreditBalance, #OrderId, #MasterEntryId, #EntryType, NEWID()
if ##ERROR <> 0
begin
rollback
raiserror ('Can not insert entry record', 16, 1)
return 1
end
commit tran
set #EntryId = SCOPE_IDENTITY()
return 0
END
go
You are executing multiple ROLLBACK commands when you should only execute it once. A rollback will lower the transaction count from any amount higher than 0 directly to 0, so if you execute 3 BEGIN TRANSACTION, your ##TRANCOUNT is 3 and a rollback will set it to 0. The problem is that you are executing a rollback inside the called SP (the nested one) and again after the SP returns.
You can see the problem with this example:
BEGIN TRANSACTION
SELECT ##TRANCOUNT -- 1
BEGIN TRANSACTION
SELECT ##TRANCOUNT -- 2
ROLLBACK
SELECT ##TRANCOUNT -- 0
ROLLBACK -- The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.
And this is the failing execution route from your SP:
CREATE PROCEDURE [dbo].[RevokeOrder]
#OrderId int = null
AS
begin tran -- Create a transaction here (TRANCOUNT = 1)
if (...)
begin
EXECUTE #RC = [dbo].[AddJournalEntry] -- Executes a rollback inside
if ##ERROR <> 0 or #RC <> 0
begin
rollback -- When the execution reaches this rollback, TRANCOUNT is 0 and the rollback fails
raiserror ('Revoke order process. Can not add reverse blocked quote amount journal entry', 16, 1)
return 4
end
end
END
And the SP being called:
CREATE PROCEDURE [dbo].[AddJournalEntry]
AS
BEGIN
begin tran -- TRANCOUNT = 2
if (#DebitBalance < 0 and #ToIncrease = 'debit') or (#DebitBalance > 0 and #ToIncrease = 'credit')
begin
rollback -- Undoes all changes from the start of the first BEGIN TRAN and sets TRANCOUNT to 0
set #Error = 'Debit account balance can not be less than 0. ' + #DebitAccountTitle
raiserror (#Error, 16, 1)
return 5
end
END
I'd recommend using TRY/CATCH blocks and doing the ROLLBACK on the CATCH. This would be like the following:
CREATE PROCEDURE [dbo].[RevokeOrder]
#OrderId int = null
AS
BEGIN TRY
begin tran
if (...)
begin
EXECUTE #RC = [dbo].[AddJournalEntry]
if ##ERROR <> 0 or #RC <> 0
begin
raiserror ('Revoke order process. Can not add reverse blocked quote amount journal entry', 16, 1)
return 4
end
end
COMMIT
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0 -- Might want to check XACT State also
ROLLBACK
-- Additional logging/fixing stuff
END CATCH
END
For detailed explanation on SQL Server error handling, check this post.
I'm having this error when I try to execute this code:
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 0, current count = 1.
I know the problem is on the sp [dbo].[QueueInsert], the sp has an error and it goes directly to the catch. It's funny because the first one (EXEC [dbo].[BacthInsert]) is inserting a summary record and after running the sp, I see the record, so is doing a commit and not doing a rollback. What's wrong with this code? thanks!
CREATE PROCEDURE [cnfg].[SendEmail]
(
,#Employees [dbo].[Employees] readonly
,#ApplicationName NVARCHAR(256)
,#ErrorMsg NVARCHAR(300) = NULL OUTPUT
)
AS
BEGIN
DECLARE #ReturnVal INT
DECLARE #ApplicationId UNIQUEIDENTIFIER
DECLARE #NewIdBatch INT
DECLARE #ID INT
DECLARE #EmployeeId INT
DECLARE #Index INT = 1
DECLARE #Total INT
SET NOCOUNT ON;
SET XACT_ABORT ON;
SET #ReturnVal = 0;
SET #ErrorMsg = '';
SET #ApplicationId = [GetId](#ApplicationName);
IF (#ApplicationId IS NULL)
BEGIN
SET #ReturnVal = 1;
SET #ErrorMsg = 'The Application Name does not exist in the database';
Goto ProcedureExit
END
----------------------------------------------------------
BEGIN TRY -- Start Main TRY
----------------------------------------------------------
BEGIN TRANSACTION;
EXEC [dbo].[BacthInsert]
#ParameterId = 1
,#ID = #NewSendEmailBatchId OUTPUT
,#ErrorMsg = #ErrorMsg OUTPUT
IF ( #ErrorMsg <> '' )
BEGIN
SET #ReturnVal = 1;
SET #ErrorMsg = 'There was an error trying to insert data into [dbo].[BacthInsert] table';
RAISERROR(#ErrorMsg, 16, 1)
END
SELECT ROW_NUMBER() OVER ( ORDER BY EmployeeId ) Row,
EmployeeId
INTO #EmpIds
FROM #Employees
SELECT #Total = COUNT(*) FROM #EmpIds
WHILE ( #Index <= #Total )
BEGIN
SELECT #EmployeeId=EmployeeId FROM #EmpIds WHERE Row = #Index
EXEC [dbo].[QueueInsert]
#SendEmailBatchId = #NewIdBatch
,#ID = #ID OUTPUT
,#ErrorMsg = #ErrorMsg OUTPUT
IF ( #ErrorMsg <> '' )
BEGIN
SET #ReturnVal = 1;
SET #ErrorMsg = 'There was an error trying to insert data into [dbo].[QueueInsert] table';
RAISERROR(#ErrorMsg, 16, 1)
END
SET #Index+=1;
END
COMMIT TRANSACTION;
----------------------------------------------------------
END TRY -- End Main TRY
----------------------------------------------------------
----------------------------------------------------------
BEGIN CATCH -- Start Main CATCH
----------------------------------------------------------
SELECT ERROR_MESSAGE()
IF (XACT_STATE()) = -1
BEGIN
ROLLBACK TRANSACTION;
END;
----------------------------------------------------------
END CATCH -- End Main CATCH
----------------------------------------------------------
ProcedureExit:
RETURN #ReturnVal;
END
I have a lot of stored procedures. But I am only getting Request Timeout sometimes only for this SP ?
ALTER PROCEDURE [dbo].[Insertorupdatedevicecatalog]
(#OS NVARCHAR(50)
,#UniqueID VARCHAR(500)
,#Longitude FLOAT
,#Latitude FLOAT
,#Culture VARCHAR(10)
,#Other NVARCHAR(200)
,#IPAddress VARCHAR(50)
,#NativeDeviceID VARCHAR(50))
AS
BEGIN
SET NOCOUNT ON;
DECLARE #TranCount INT;
SET #TranCount = ##TRANCOUNT;
DECLARE #OldUniqueID VARCHAR(500) = ''-1'';
SELECT #OldUniqueID = [UniqueID] FROM DeviceCatalog WHERE (#NativeDeviceID != '''' AND [NativeDeviceID] = #NativeDeviceID);
BEGIN TRY
IF #TranCount = 0
BEGIN TRANSACTION
ELSE
SAVE TRANSACTION Insertorupdatedevicecatalog;
DECLARE #Geo GEOGRAPHY = geography::STGeomFromText(''POINT('' + CONVERT(VARCHAR(100), #Longitude) + '' '' + CONVERT(VARCHAR(100), #Latitude) + '')'', 4326);
IF EXISTS(SELECT 1 FROM DeviceCatalog WHERE [UniqueID] = #UniqueID)
BEGIN
DECLARE #OldGeo GEOGRAPHY
,#OldCity NVARCHAR(100)
,#OldCountry NVARCHAR(100)
,#OldAddress NVARCHAR(100);
SELECT #OldGeo = [LastUpdatedLocationFromJob]
,#OldCity = [City]
,#OldCountry = [Country]
,#OldAddress = [Address]
FROM DeviceCatalog
WHERE [UniqueID] = #UniqueID;
UPDATE DeviceCatalog
SET [OS] = #OS
,[Location] = #Geo
,[Culture] = #Culture
,[Other] = #Other
,[IPAddress] = #IPAddress
WHERE [UniqueID] = #UniqueID;
IF (#OldGeo IS NULL OR #OldAddress IS NULL OR #OldCity IS NULL OR #OldCountry IS NULL OR ISNULL(#Geo.STDistance(#OldGeo) / 1000,0) > 50)
BEGIN
UPDATE DeviceCatalog
SET [Lastmodifieddate] = Getdate()
WHERE [UniqueID] = #UniqueID;
END
END
ELSE
BEGIN
INSERT INTO DeviceCatalog
([OS]
,[UniqueID]
,[Location]
,[Culture]
,[Other]
,[IPAddress]
,[NativeDeviceID])
VALUES (#OS
,#UniqueID
,#Geo
,#Culture
,#Other
,#IPAddress
,#NativeDeviceID);
IF(#OldUniqueID != ''-1'' AND #OldUniqueID != #UniqueID)
BEGIN
EXEC DeleteOldAndroidDeviceID #OldUniqueID, #UniqueID;
END
END
LBEXIT:
IF #TranCount = 0
COMMIT;
END TRY
BEGIN CATCH
DECLARE #Error INT, #Message VARCHAR(4000), #XState INT;
SELECT #Error = ERROR_NUMBER() ,#Message = ERROR_MESSAGE() ,#XState = XACT_STATE();
IF #XState = -1
ROLLBACK;
IF #XState = 1 AND #TranCount = 0
rollback
IF #XState = 1 AND #TranCount > 0
ROLLBACK TRANSACTION Insertorupdatedevicecatalog;
RAISERROR (''Insertorupdatedevicecatalog: %d: %s'', 16, 1, #error, #message) ;
END CATCH
END
The timeout occurs due to two updates to same table inside same transaction. You could avoid it with a case statement. Also whole IF ELSE can be replaced with a merge.
MERGE INTO DeviceCatalog DC
USING (SELECT #UniqueID AS UniqueID) T ON (DC.UniqueID = T.UniqueID)
WHEN MATCHED THEN
UPDATE SET [OS] = #OS
,[Location] = #Geo
,[Culture] = #Culture
,[Other] = #Other
,[IPAddress] = #IPAddress
,[Lastmodifieddate] = (CASE
WHEN (LastUpdatedLocationFromJob IS NULL OR [Address] IS NULL OR [City] IS NULL OR [Country] IS NULL OR ISNULL(#Geo.STDistance(LastUpdatedLocationFromJob) / 1000,0) > 50)
THEN Getdate()
ELSE [Lastmodifieddate]
END)
WHEN NOT MATCHED THEN
INSERT INTO DeviceCatalog
([OS]
,[UniqueID]
,[Location]
,[Culture]
,[Other]
,[IPAddress]
,[NativeDeviceID])
VALUES (#OS
,#UniqueID
,#Geo
,#Culture
,#Other
,#IPAddress
,#NativeDeviceID)
WHEN NOT MATCHED BY SOURCE AND #OldUniqueID != ''-1'' AND #OldUniqueID != #UniqueID THEN
DELETE;
Try it and check whether this is what you expected.
Already discussed here
You can achieve it using sp_getapplock in TSQL.
But you need a wrapper storedproc or batch for this. Check the following example it will help you to desing your wrapper sp/batch statement.
Sample Code Snippet
Create table MyTable
(
RowId int identity(1,1),
HitStartedAt datetime,
HitTimestamp datetime,
UserName varchar(100)
)
Go
Create proc LegacyProc (#user varchar(100), #CalledTime datetime)
as
Begin
Insert Into MyTable
Values(#CalledTime, getdate(), #user);
--To wait for 10 sec : not required for your procedures, producing the latency to check the concurrent users action
WAITFOR DELAY '000:00:10'
End
Go
Create Proc MyProc
(
#user varchar(100)
)
as
Begin
Declare #PorcName as NVarchar(1000), #CalledTime datetime
Begin Tran
--To get the Current SP Name, it should be unique for each SP / each batch
SET #PorcName = object_name(##ProcID)
SET #CalledTime = Getdate()
--Lock the Current Proc
Exec sp_getapplock #Resource = #PorcName, #LockMode = 'Exclusive'
--Execute Your Legacy Procedures
Exec LegacyProc #user, #CalledTime
--Release the lock
Exec sp_releaseapplock #Resource = #PorcName
Commit Tran
End
You are doing two seperate updates on the DeviceCatalog table where [UniqueID] = #UniqueID in the same transaction.
I bet your locking/request timeout issue is happening when:
IF (#OldGeo IS NULL OR #OldAddress IS NULL OR #OldCity IS NULL OR #OldCountry IS NULL OR ISNULL(#Geo.STDistance(#OldGeo) / 1000,0) > 50) is true.
Try something like this in place of the two updates.
Obviously test in dev first.
In the else clause, you want to have it insert something if the when is false. Here I am just inserting the current before update field contents.
UPDATE DeviceCatalog
SET [OS] = #OS
,[Location] = #Geo
,[Culture] = #Culture
,[Other] = #Other
,[IPAddress] = #IPAddress
,[Lastmodifieddate] =
case when (
#OldGeo is NULL
OR
#OldAddress is NULL
OR
#OldCity is NULL
OR
#OldCountry is NULL
OR
ISNULL(#Geo.STDistance(#OldGeo) / 1000,0) > 50
) then Getdate()
else [Lastmodifieddate]
end
WHERE [UniqueID] = #UniqueID
Hello Every One The Following Error Comes To Me Suddenly When I Changed Simple And Few Thing On My Stored Procedure Code And It Was Working Great And If I Cleared The Updated Code It Works Fine Again So I Do Not Know What Is The Reason
And Here Is The Error "The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction"
Thanks In Advance
ALTER Procedure [dbo].[xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]
#English Bit = 0 ,
#ID BigInt = NULL Output ,
#Company_ID SmallInt = NULL ,
#Cust_ID NVarChar (20) = NULL ,
#Cust_Cat NVarChar (10) = NULL ,
#Debit_Limit Decimal (18,3) = NULL ,
#From_Date NVarChar (19) = NULL ,
#To_Date NVarChar (19) = NULL ,
#User_ID NVarChar(50) = NULL
As
BEGIN
Create Table #Errors (ErrorNumber int Not Null, ErrorValue nvarchar(300) Collate Arabic_CI_AS Null);
Begin Tran trn_INV_CustDebLim_setupInsert;
Begin Try
Insert Into INV_Cust_Debit_Limit_setup
( Company_ID , Cust_ID , Cust_Cat , Debit_Limit , From_Date , To_Date )
Values
( #Company_ID , #Cust_ID , #Cust_Cat , #Debit_Limit , #From_Date , #To_Date )
set #ID = ##IDENTITY
-- From Here Is New Part --
declare #str nvarchar(50)
IF(#Cust_ID IS NOT NULL)
set #str = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx ' + #Cust_ID
IF(#Cust_Cat IS NOT NULL)
set #str += 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx ' + #Cust_Cat
set #str += ' xxxxx' +#Debit_Limit + ' xxxx xx' +#From_Date
IF(#English = 1)
BEGIN
IF(#Cust_ID IS NOT NULL)
set #str = 'Credit Limit Added On Customer ' + #Cust_ID
IF(#Cust_Cat IS NOT NULL)
set #str += 'Credit Limit Added On Customer Category ' + #Cust_Cat
set #str = ' With Value ' +#Debit_Limit + ' From Date ' +#From_Date
END
exec usp_GLApplicationAudit #Company_ID , NULL , 10 , #User_ID , #str ,#ID ,10, NULL , NULL ,NULL ,NULL,NULL,'SAl'
-- To Here Is New Part --
End Try
Begin Catch
Insert #Errors Values(1002,ERROR_MESSAGE());
Goto Finished;
End Catch
-- Return Error Records
Finished:
-- retrieve Errors and commit/Rollbak Trans.
If (Select count(E.ErrorNumber)
From #Errors E Left Join GVT_Errors G
On E.ErrorNumber = G.Err_Number
Where G.Err_Type=0 ) > 0
Begin
-- The Following are Errors
Select E.ErrorNumber As [Err_No], G.MessageA + ': ' + E.ErrorValue As [Err_Desc], Err_Source, dbo.fn_GetItemDescription('Err_Type',Cast(Err_Type As nvarchar), null, null, null, null, 0) As Err_Type_Desc, Err_Type, SeverityLevel As [Severity], CategoryID
From #Errors E Left Join GVT_Errors G
On E.ErrorNumber = G.Err_Number;
Rollback Tran trn_INV_CustDebLim_setupInsert;
End
Else
Begin
-- The Following Not Errors They are Warnings or Information
Select E.ErrorNumber As [Err_No], G.MessageA + ': ' + E.ErrorValue As [Err_Desc], Err_Source, dbo.fn_GetItemDescription('Err_Type',Cast(Err_Type As nvarchar), null, null, null, null, 0) As Err_Type_Desc, Err_Type, SeverityLevel As [Severity], CategoryID
From #Errors E Left Join GVT_Errors G
On E.ErrorNumber = G.Err_Number;
Commit Tran trn_INV_CustDebLim_setupInsert;
End
DROP Table #Errors;
END
In the CATCH code you must check the state of XACT_STATE() and act accordingly. For a procedure template that handles transactions and try/catch blocks correctly see Exception Handling and Nested Transactions:
create procedure [usp_my_procedure_name]
as
begin
set nocount on;
declare #trancount int;
set #trancount = ##trancount;
begin try
if #trancount = 0
begin transaction
else
save transaction usp_my_procedure_name;
-- Do the actual work here
lbexit:
if #trancount = 0
commit;
end try
begin catch
declare #error int, #message varchar(4000), #xstate int;
select #error = ERROR_NUMBER(), #message = ERROR_MESSAGE(), #xstate = XACT_STATE();
if #xstate = -1
rollback;
if #xstate = 1 and #trancount = 0
rollback
if #xstate = 1 and #trancount > 0
rollback transaction usp_my_procedure_name;
raiserror ('usp_my_procedure_name: %d: %s', 16, 1, #error, #message) ;
end catch
end
I'm noob at stored procedures, I have created a stored procedure that take some parameters from C# page, then send back result as OUTPUT parameter.
I need to do some calculation to get end date, so I end up using a lot of IF statements. However, when I create the stored procedure I get error that I didn't know how to solve, every thing seems correct!.
Here is the stored procedure code:
CREATE PROCEDURE sp_RenewSubscription
-- Add the parameters for the stored procedure here
#Reference nvarchar(100),
#SubscribtionID nvarchar(100),
#Months int,
#Result nvarchar(200) OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #EndDate as nvarchar;
DECLARE #MonthCounts as int;
IF NOT EXISTS(SELECT [Reference] FROM [Norton].[dbo].[SubscriptionStatus] WHERE [Reference] = #Reference)
SET #Result = '0: Reference ID not found'
ELSE
IF NOT EXISTS(SELECT [Reference] FROM [Norton].[dbo].[SubscriptionStatus] WHERE [Reference] = #Reference AND [SubscribtionID] = #SubscribtionID)
SET #Result = '0: Subscribtion ID not found'
ELSE
BEGIN
SELECT TOP 1 #EndDate = [EndDate], #MonthCounts = [SubscriptionMonthCount] FROM [Norton].[dbo].[SubscriptionStatus] WHERE [Reference] = #Reference AND [SubscribtionID] = #SubscribtionID
IF #EndDate = '0'
BEGIN
UPDATE [Norton].[dbo].[SubscriptionStatus]
SET [SubscriptionMonthCount] = #Months + #MonthCounts
WHERE [Reference] = #Reference AND [SubscribtionID] = #SubscribtionID
END
ELSE
BEGIN
UPDATE [Norton].[dbo].[SubscriptionStatus]
SET [SubscriptionMonthCount] = #Months
WHERE [Reference] = #Reference AND [SubscribtionID] = #SubscribtionID
END
SET #Result = '1: Done Successfully'
END
GO
END
GO
This is error I got:
Msg 102, Level 15, State 1, Procedure sp_RenewSubscription, Line 44
Incorrect syntax near 'END'.
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near 'END'.*
Thanks,
Remove the go from before the end of the procedure.
ie
END
SET #Result = '1: Done Successfully'
END
GO --- <-- get rid of this
END
Try this:
CREATE PROCEDURE Sp_renewsubscription
-- Add the parameters for the stored procedure here
#Reference NVARCHAR(100),
#SubscribtionID NVARCHAR(100),
#Months INT,
#Result NVARCHAR(200) output
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET nocount ON;
DECLARE #EndDate AS NVARCHAR;
DECLARE #MonthCounts AS INT;
IF NOT EXISTS(SELECT [reference]
FROM [Norton].[dbo].[subscriptionstatus]
WHERE [reference] = #Reference)
SET #Result = '0: Reference ID not found'
ELSE IF NOT EXISTS(SELECT [reference]
FROM [Norton].[dbo].[subscriptionstatus]
WHERE [reference] = #Reference
AND [subscribtionid] = #SubscribtionID)
SET #Result = '0: Subscribtion ID not found'
ELSE
BEGIN
SELECT TOP 1 #EndDate = [enddate],
#MonthCounts = [subscriptionmonthcount]
FROM [Norton].[dbo].[subscriptionstatus]
WHERE [reference] = #Reference
AND [subscribtionid] = #SubscribtionID
IF #EndDate = '0'
UPDATE [Norton].[dbo].[subscriptionstatus]
SET [subscriptionmonthcount] = #Months + #MonthCounts
WHERE [reference] = #Reference
AND [subscribtionid] = #SubscribtionID
ELSE
UPDATE [Norton].[dbo].[subscriptionstatus]
SET [subscriptionmonthcount] = #Months
WHERE [reference] = #Reference
AND [subscribtionid] = #SubscribtionID
SET #Result = '1: Done Successfully'
END
END
GO