SQL TRANSACTION Begin End mismatch? - sql

Although I am able to create stored procedure successfully I am getting "TRANSACTION BEGIN END MISMATCH" error upon using it. The stored Procedure works fine when I remove transaction.
ALTER PROCEDURE Proc_LoanRepayment #LASAcctno [VARCHAR] (15),
#EntryDate [VARCHAR] (8),
#ValueDate [VARCHAR] (8),
#ModeofPayment VARCHAR(20),
#ChqNo VARCHAR(20),
#ChqDate VARCHAR(8),
#ChqAmt MONEY,
#CstBnkNo VARCHAR(20),
#Cstbnkid VARCHAR(20),
#CmpBnkNo VARCHAR(20),
#Cmpbnkid VARCHAR(20),
#Narration1 [VARCHAR] (100),
#Narration2 [VARCHAR] (100),
#EntryType VARCHAR(30),
#PostingString [VARCHAR] (max)
AS
BEGIN TRAN
DECLARE #string AS VARCHAR(max)
DECLARE Cur_A CURSOR FOR
SELECT *
FROM dbo.split(#PostingString, ',')
OPEN Cur_a
FETCH NEXT FROM cur_a INTO #string
WHILE ##FETCH_STATUS = 0
BEGIN
IF ( object_id('TempDB..#Temp') ) IS NOT NULL
BEGIN
DROP TABLE #Temp
END
-- declare #temp table (srno int identity,items varchar(max))
SELECT *
INTO #temp
FROM dbo.Split(#string, '|')
DECLARE #LoanNo AS VARCHAR(20),
#BankAcct AS VARCHAR(20),
#TDS AS MONEY,
#LASPAC AS MONEY,
#INTRND AS MONEY,
#INTRAC AS MONEY,
#STAXPLRVL AS MONEY,
#PNLINT AS MONEY,
#OVRDUEINT AS MONEY,
#STMPDTYRVL AS MONEY,
#PROFESRVL AS MONEY,
#DOCCHGRVL AS MONEY,
#CHQBNCRVL AS MONEY
ALTER TABLE #temp
ADD srno INT IDENTITY
SELECT #LoanNo = items
FROM #temp
WHERE srno = 1
SELECT #bankAcct = items
FROM #temp
WHERE srno = 2
SELECT #TDS = items
FROM #temp
WHERE srno = 3
SELECT #LASPAC = items
FROM #temp
WHERE srno = 4
SELECT #INTRND = items
FROM #temp
WHERE srno = 5
SELECT #INTRAC = items
FROM #temp
WHERE srno = 6
SELECT #STAXPLRVL = items
FROM #temp
WHERE srno = 7
SELECT #PNLINT = items
FROM #temp
WHERE srno = 8
SELECT #OVRDUEINT = items
FROM #temp
WHERE srno = 9
SELECT #STMPDTYRVL = items
FROM #temp
WHERE srno = 10
SELECT #PROFESRVL = items
FROM #temp
WHERE srno = 11
SELECT #DOCCHGRVL = items
FROM #temp
WHERE srno = 12
SELECT #CHQBNCRVL = items
FROM #temp
WHERE srno = 13
INSERT INTO Tbl_BankEntry
(LASAcctno,
EntryDate,
ValueDate,
ModeofPayment,
ChqNo,
ChqDate,
ChqAmt,
CstBnkNo,
Cstbnkid,
CmpBnkNo,
Cmpbnkid,
Narration1,
Narration2,
LoanNo,
BankAcct,
TDS,
LASPAC,
INTRND,
INTRAC,
STAXPLRVL,
PNLINT,
OVRDUEINT,
STMPDTYRVL,
PROFESRVL,
DOCCHGRVL,
CHQBNCRVL,
status,
mkrdt,
mkrid,
EntryType)
VALUES ( #LASAcctno,
#EntryDate,
#ValueDate,
#ModeofPayment,
#ChqNo,
#ChqDate,
#ChqAmt,
#CstBnkNo,
#Cstbnkid,
#CmpBnkNo,
#Cmpbnkid,
#Narration1,
#Narration2,
#LoanNo,
#BankAcct,
#TDS,
#LASPAC,
#INTRND,
#INTRAC,
#STAXPLRVL,
#PNLINT,
#OVRDUEINT,
#STMPDTYRVL,
#PROFESRVL,
#DOCCHGRVL,
#CHQBNCRVL,
'P',
GETDATE(),
'c97176',
#EntryType )
FETCH NEXT FROM Cur_a INTO #string
END
CLOSE cur_a
DEALLOCATE cur_a
RETURN
COMMIT TRAN

Your RETURN statement is before your COMMIT statement.
Suggest you look into #Martin Smith's sugegstion of using table valued parameters rather than splitting strings (SQL Server 2008+), and # Damien_The_Unbeliever's suggestion of the expected ordering.
Also, try to rewrite procedure so that it doesn't require a cursor, and that you do the least amount possible of work inside the transaction.
Also, look at TRY/CATCH and checking whether there is an active transaction (##TRANCOUNT) before commiting.

Related

Insert into table within function

I would like to insert the #OBV's value into a table inside the function. What is the correct way to achieve it?
alter function CalculateOnBalanceVolume (
#operation varchar(3),
#volume money
)
returns char(4) as
begin
declare #prevOBV as money,
#OBV as money
set #prevOBV = (
select top 1 OnBalanceVolume
from OnBalanceVolume
order by EventTime desc
)
if (#operation = 'add') set #OBV = #prevOBV + #volume
if (#operation = 'sub') set #OBV = #prevOBV - #volume
insert into OBVTable values (#OBV) // error
return #OBV
end;
Functions cannot perform any actions known as side-effecting which includes inserting or updating or deleting from tables, so you cannot use a Function for this.
To use a stored procedure you might have:
create procedure CalculateOnBalanceVolume
#operation varchar(3),
#volume decimal(9,2),
#OBV decimal(9,2) output
as
select top (1) #Obv=OnBalanceVolume +
case when #Operation='add' then #volume else -#volume end
from OnBalanceVolume
order by EventTime desc
insert into OBVTable values (#OBV)
go
And then to invoke the procedure and get your output value you would do for example:
declare #OBV decimal(9,2)
exec CalculateOnBalanceVolume 'add', 100, #OBV output
select #OBV as OutputValue

Failed to insert to a declared type table in stored procedure

my stored procedure failed to insert to a declared table type, there's already an insert query but when I select * from #AktaFiducia it's empty, can someone help me to identify what could I be doing wrong on the query below?
ALTER PROCEDURE [dbo].[InsertFiducia]
#BatchNo Varchar(30),
#LoginID varchar(50),
#Message varchar(1000) output
AS
BEGIN
BEGIN TRY
BEGIN TRAN AKTAFiducia
declare #AktaFiducia table
(
ID int IDENTITY PRIMARY KEY,
BranchID varchar(3),
ApplicationID varchar(20),
SeqNo varchar(3),
AktaNo varchar(50),
AktaDate date,
CertificateNo varchar(50),
CertificateDate date,
InvoiceNo varchar(50),
InvoiceDate date,
InvoiceNote varchar(200),
FiduciaFee numeric(17,2),
BusinessDate Date,
ReceivedBy varchar(50),
NotaryID varchar(20),
AgreementNo varchar(20),
ServiceFee numeric(17,2),
FiduciaSeqNo int
)
insert into #AktaFiducia
select
fd.BranchID,
fd.ApplicationID,
fd.AssetSeqNo,
ufr.AktaNo,
ufr.AktaDate,
fd.CertificateNo,
fd.CertificateDate,
ufr.InvoiceNumber,
ufr.InvoiceDate,
fd.InvoiceNotes,
NotaryCharge.AktaFee,
GETDATE(),
'Upload-System',
fd.NotaryId,
ufr.NoKontrak,
NotaryCharge.ServiceFee,
FiduciaSeqNo
from UploadFidusiaAktaRecieve ufr with (nolock)
inner join dbo.Agreement agr with (nolock) on agr.AgreementNo = ufr.NoKontrak
inner join dbo.Fiducia fd with (nolock) on fd.BranchID = agr.BranchID and fd.ApplicationID = agr.ApplicationID
and fd.AssetSeqNo = ufr.AssetSeqNo and ISNULL(fd.CustomerID,'') = ISNULL(ufr.CustomerID,'')
left join dbo.NotaryCharge with (nolock) on NotaryCharge.NotaryID = fd.NotaryId and TotalOTR between NotaryCharge.OTRFrom and NotaryCharge.OTRUntil
and AssetTypeID = case when ProductType ='DEMotor' then 'MOTOR' else 'MOBIL'end
where IsProses = 0 and BatchNo = #BatchNo
select * from #AktaFiducia
SET #message = ''
COMMIT TRAN AKTAFiducia
END TRY
BEGIN CATCH
ROLLBACK TRAN AKTAFiducia
SET #message = ERROR_MESSAGE()
END CATCH
END

SQL While Loop Insert with values from another table

I am trying to create a SQL While loop that will update a temp table with values from another table. Values from the other table:
477286
560565
499330
391827
127375
526354
501736
357359
410433
500946
261297
377667
135931
235691
247239
143672
548752
471945
...
Wrote the following, however, it only inserts the last value multiple times over.
Here is the code:
USE Reports
GO
CREATE TABLE #TempTable (CreatedByID int, LastUpdatedByID int, ID int,
AlertDE int, Alert char(50), StartDTTM datetime, EndDTTM datetime,
IsInactiveFLAG char(1),AlertDetails char(1));
DECLARE #numrows INT
SELECT #numrows = COUNT(*) FROM [Reports].[dbo].[Eligible]
DECLARE #id int
DECLARE #LoopCount INT = 1
DECLARE #count int = #numrows
SELECT #id = [id] FROM [Reports].[dbo].[Eligible]
WHILE (#LoopCount <= #count)
BEGIN
INSERT INTO #TempTable (CreatedByID, LastUpdatedByID, ID, AlertDE, Alert, StartDTTM, EndDTTM, IsInactiveFLAG,AlertDetails)
VALUES (52,52,#id,0,'Eligible',CURRENT_TIMESTAMP,'1900-01-01
00:00:00.000','N','')
SET #LoopCount = #LoopCount + 1
END
SELECT * FROM #TempTable
DROP TABLE #TempTable
I am assuming I have to tell it to loop through the values in the other table somehow but I am not positive if that is the right approach or if in general I am taking the long way around the bus.
Why are you using a loop? You can do this with an insert . . . select statement:
INSERT INTO #TempTable (CreatedByID, LastUpdatedByID, ID, AlertDE, Alert, StartDTTM, EndDTTM, IsInactiveFLAG, AlertDetails)
SELECT 52, 52, e.id, 0, 'Eligible', CURRENT_TIMESTAMP, '1900-01-01 00:00:00.000', 'N', ''
FROM [Reports].[dbo].[Eligible] e ;
See eg https://www.w3schools.com/sql/sql_insert_into_select.asp for more info.
GMR, I found a way to accomplish my need which is similar to yours. Hopefully this will help you too.
DECLARE
#LoopId int
,#TheOrderNumber varchar(20)
DECLARE #CheckThisItem TABLE
(
LoopId int not null identity(1,1)
,TheOrderNumber varchar(20) not null
)
INSERT #CheckThisItem
SELECT Order_Number AS TheOrderNumber
FROM [dbo].[Table_Storing_Order_Number] ORDER BY Order_Number ASC
SET #LoopId = ##rowcount
WHILE #LoopId > 0
BEGIN
SELECT #TheOrderNumber = TheOrderNumber
FROM #CheckThisItem
WHERE LoopId = #LoopId
-- Start inserting record pulled for while loop
INSERT [dbo].[The_Destination_Table]
SELECT TOP (1)
A, B, C, D
FROM [dbo].[Source_Table] ST
WHERE
ST.Order_Number = #TheOrderNumber
-- Set number to reduce loop counter
SET #LoopId = #LoopId - 1
END;

Autogenerate numbers based on "Group" in GroupByExpression RadGrid and display it in RadGrid

I am having a trouble in implementing below requirement.
Current RadGrid: Below is the RadGrid in which I am using GroupByExpressions
to display/show data grouped with "Business Unit" column.
In RadGrid column 2nd(InvoiceLineNo) and 3rd(InvoiceNo), I am auto generating the numbers using Stored Procedure.
i.e., for "InvoiceLineNo" column, Autogenerated No's are: 01,02,03,04,05,06,07,08.......n
for "InvoiceNo" column, Autogenerated No's are: 15100001, 15100002, 15100003........n
where, 15 is a "year" and 100001 are "running numbers"
Requirement is: I want to show the "InvoiceLineNo" column data as Group wise.
Example:
for 1st "Business Unit" group (i.e., SUNWAY LEISURE SDN BHD (CARNIVAL)),
InvoiceLineNo shall be: 01,02,03,04,05,06,07,08
for 2nd "Business Unit" group (i.e., SUNWAY MALL PARKING SDN BHD),
InvoiceLineNo shall be: 01,02,03,04,05,06,07,08
Similarly, I want to show the "InvoiceNo" column data as Group wise.
Example:
for 1st "Business Unit" group (i.e., SUNWAY LEISURE SDN BHD (CARNIVAL)),
InvoiceNo shall be: 15100001,15100001,15100001,15100001,15100001,15100001,15100001,15100001
for 2nd "Business Unit" group (i.e., SUNWAY MALL PARKING SDN BHD),
InvoiceNo shall be: 15100002,15100002,15100002,15100002,15100002,15100002,15100002,15100002
"InvoiceNo" column data will always be unique for different "Business Unit".
I want output to be like below snapshot:
I can autogenerate the numbers serial wise but I am not getting how to autogenerate the 2 column values based on Group and show them like
that.
Please help me to achieve it. Please do reply.
Thanks in advance.
Edit:
Below is the Stored Procedure I am using to generate autogenerated numbers in RadGrid's 2 column's:
ALTER PROCEDURE [dbo].[SDM_Assign_RunningNo]
-- Add the parameters for the stored procedure here
#TableName as nvarchar(50),
#NewID as nvarchar(50) OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #rn_year as nvarchar(50)
--Get Year From table
SELECT #rn_year =RNYear FROM dbo.SDM_Tran_RunningNo
WHERE RNYear= YEAR(GetDate())
--get last 2 digits of year
Declare #2digit_rn_year as nvarchar(50)
SELECT #2digit_rn_year = RNYear % 100 FROM dbo.SDM_Tran_RunningNo
WHERE RNYear= YEAR(GetDate())
IF #TableName='SDM_Tran_GenerateInvoice_No'
BEGIN
SELECT #NewID=Next_InvoiceNo FROM dbo.SDM_Tran_RunningNo
WHERE RNYear=#rn_year
UPDATE dbo.SDM_Tran_RunningNo
SET Next_InvoiceNo=Next_InvoiceNo+1
WHERE RNYear=#rn_year
SET #NewID = #2digit_rn_year +'1'+RIGHT('000000' + CAST(#NewID as varchar(10)), 5)
END
ELSE IF #TableName='SDM_Tran_GenerateInvoice_LineNo'
BEGIN
SELECT #NewID=Next_InvoiceLineNo FROM dbo.SDM_Tran_RunningNo
WHERE RNYear=#rn_year
UPDATE dbo.SDM_Tran_RunningNo
SET Next_InvoiceLineNo=Next_InvoiceLineNo+1
WHERE RNYear=#rn_year
SET #NewID = RIGHT('000000' + CAST(#NewID as varchar(10)), 2)
END
END
And then inserting the 2 column values into Table as below (using Stored Procedure),
to display it in RadGrid:
DECLARE #InvoiceNo as nvarchar(50)
--SP to generate new Invoice No
EXEC dbo.SDM_Assign_RunningNo
#TableName='SDM_Tran_GenerateInvoice_No',
#NewID = #InvoiceNo OUTPUT
DECLARE #InvoiceLineNo as nvarchar(50)
--SP to generate new Invoice Line No
EXEC dbo.SDM_Assign_RunningNo
#TableName='SDM_Tran_GenerateInvoice_LineNo',
#NewID = #InvoiceLineNo OUTPUT
INSERT INTO SDM_Tran_GenerateInvoice
VALUES (#InvoiceID,
#SPfoID,
#InvoiceLineNo, #InvoiceNo, #InvoiceType,
#BillingIDfoID, #BusinessUnit, #DirectCost,
#Status, GETDATE(), #AccountCode)
This is a concept... you might need to modify it to suit your requirement.
DECLARE #Temp TABLE (
InvoiceID nvarchar(50),
SPfoID nvarchar(50),
InvoiceLineNo nvarchar(50),
InvoiceNo nvarchar(50),
InvoiceType nvarchar(50),
BillingIDfoID nvarchar(50),
BusinessUnit nvarchar(2000),
DirectCost nvarchar(2000),
Status nvarchar(10),
Date datetime,
AccountCode nvarchar(1000)
)
DECLARE #Temp1 TABLE (
OrderID INT IDENTITY, -- Added This so It Will follow this new Identity Row
InvoiceID nvarchar(50),
SPfoID nvarchar(50),
InvoiceLineNo nvarchar(50),
InvoiceNo nvarchar(50),
InvoiceType nvarchar(50),
BillingIDfoID nvarchar(50),
BusinessUnit nvarchar(2000),
DirectCost nvarchar(2000),
Status nvarchar(10),
Date datetime,
AccountCode nvarchar(1000)
)
DECLARE #CompanyValue nvarchar(2000) = '' --BusinessUnit datatype
DECLARE #Counter nvarchar(50) = '0' --InvoiceNo datatype
DECLARE #InvoiceLine INT = 1
DECLARE #Year INT = YEAR(GETDATE())
DECLARE #ShortYear VARCHAR(2) = SUBSTRING(CONVERT(VARCHAR(4), #Year), 3, 2)
EXEC dbo._RunningNo
#TableName='Invoice',
#NewID = InvoiceID --OUTPUT
INSERT INTO #Temp (InvoiceID, SPfoID, InvoiceType, BillingIDfoID, BusinessUnit, DirectCost, Status, Date, AccountCode)
SELECT InvoiceID, SPfoID, InvoiceType, BillingIDfoID, BusinessUnit, DirectCost, Status, Date, AccountCode FROM [MainTable] ORDER BY BusinessUnit
INSERT INTO #Temp1
SELECT * FROM #Temp ORDER BY BusinessUnit
SELECT * FROM #Temp
SELECT * FROM #Temp1 -- before update
--Update #Temp1 table
UPDATE #Temp1
SET
#Counter = InvoiceNo = CASE WHEN #CompanyValue = '' OR #CompanyValue = BusinessUnit THEN (CONVERT(VARCHAR(100), CONVERT(INT,#Counter) + 1)) ELSE '1' END,
#InvoiceLine = CASE WHEN #CompanyValue = '' OR #CompanyValue = BusinessUnit THEN #InvoiceLine ELSE #InvoiceLine + 1 END,
#CompanyValue = BusinessUnit,
InvoiceLineNo = #ShortYear + '10000' + CONVERT(VARCHAR(3), #InvoiceLine)
SELECT * FROM #Temp1 --after update
--Update main table
UPDATE g
SET g.InvoiceLineNo = t.InvoiceLineNo,
g.InvoiceNo = t.InvoiceNo
FROM SDM_Tran_GenerateInvoice g
INNER JOIN #Temp1 t
ON g.InvoiceID = t.InvoiceID
Select * from [MainTable]
ORDER BY BusinessUnit;

How to Split Sql Int Value into Multiple Rows

Lets say I have the following table in MS SQL 2000
Id | description | quantity |
-------------------------------
1 my desc 3
2 desc 2 2
I need to display multiple rows based on the quantity, so I need the following output:
Id | description | quantity |
-----------------------------
1 my desc 1
1 my desc 1
1 my desc 1
2 desc 2 1
2 desc 2 1
Any ideas how to accomplish this?
This works just fine, no need for any cursors on this one. It may be possible to fangle something out without a number table as well.
Note if going for this kind of solution I would keep a number table around and not recreate it every time I ran the query.
create table #splitme (Id int, description varchar(255), quantity int)
insert #splitme values (1 ,'my desc', 3)
insert #splitme values (2 ,'desc 2', 2)
create table #numbers (num int identity primary key)
declare #i int
select #i = max(quantity) from #splitme
while #i > 0
begin
insert #numbers default values
set #i = #i - 1
end
select Id, description, 1 from #splitme
join #numbers on num <= quantity
DECLARE #Id INT
DECLARE #Description VARCHAR(32)
DECLARE #Quantity INT
DECLARE #Results TABLE (Id INT, [description] VARCHAR(32), quantity INT)
DECLARE MyCursor CURSOR FOR
SELECT Id, [description], quantity
FROM
MyTable
OPEN MyCursor
FETCH NEXT FROM MyCursor INTO #Id, #Description, #Quantity
WHILE ##FETCH_STATUS = 0
BEGIN
WHILE #Quantity > 0
BEGIN
INSERT INTO #Results (
Id,
[description],
quantity
) VALUES (
#Id,
#Description,
1
)
SET #Quantity = #Quantity - 1
END
FETCH NEXT FROM MyCursor INTO #Id, #Description, #Quantity
END
CLOSE MyCursor
DEALLOCATE MyCursor
SELECT *
FROM
#Results
By the way, cursors are generally considered evil. So I will both recommend against something like this, and thank everyone in advance for their flames ;) (But it should work)
Any one looking for a CTE based solution, here is one:
create table test_splitme (Id int, description varchar(255), quantity int)
insert test_splitme values (1 ,'my desc', 3)
insert test_splitme values (2 ,'desc 2', 2)
;
--TSQL solution
with splitcte as(
select Id,description, 1 as quantity, quantity as orig_quantity, 1 as cnt
from test_splitme
union all
select Id, description, quantity, orig_quantity,cnt+1
from splitcte
where cnt < orig_quantity
)
select Id, description, quantity
from splitcte
order by 1