catching error in loop sql query - sql

I have the below insert query which selects records from the OriginalData table where everything is nvarchar(max) and inserts it into the Temp table which has specific field definitions i.e MainAccount is INT.
I am doing a row by row insert because if there is a record in OriginalData table where the MainAccount value is 'Test' the it will obviously cause a conversion error and the insert will fail.
I want to be able to capture this error. There is a field on the originalData table called "error" which I want to populate. However I want this to run thru the entire table as oppose to fail on the first error and stop.
DECLARE #RowId INT
, #MaxRowId INT
Set #RowId = 1
Select #MaxRowId = 60
WHILE(#RowId <= #MaxRowId)
BEGIN
INSERT INTO [Temp] (ExtractSource, MainAccount,RecordLevel1Code, RecordLevel2Code, RecordTypeNo, TransDate, Amount, PeriodCode, CompanyCode)
SELECT ExtractSource, MainAccount,RecordLevel1Code, RecordLevel2Code,RecordTypeNo,TransDate, Amount, PeriodCode, DataAreaId
FROM [OriginalData]
WHERE RowId = #RowId
PRINT #RowId
SET #RowId = #RowId + 1
END
select * from [Temp]

You should use TRY..CATCH block:
WHILE(#RowId <= #MaxRowId)
BEGIN
BEGIN TRY
INSERT INTO [Temp] (ExtractSource, MainAccount,RecordLevel1Code,
RecordLevel2Code, RecordTypeNo, TransDate, Amount, PeriodCode, CompanyCode)
SELECT ExtractSource, MainAccount,RecordLevel1Code, RecordLevel2Code,
RecordTypeNo,TransDate, Amount, PeriodCode, DataAreaId
FROM [OriginalData]
WHERE RowId = #RowId;
PRINT #RowId;
END TRY
BEGIN CATCH
-- error handlingg
END CATCH
SET #RowId += 1;
END

Related

Command Execution Exception: The INSERT statement conflicted with the FOREIGN KEY constraint

I have a table named student I want to assign a fee or update (if present), I am looping over them which worked fine until I deleted a student. So now whenever I run the stored procedure it shows error.
Here is my code.
ALTER PROC [dbo].[sp_AutoAssignFeeUpdate]
(
#FeeID int,
#FeeAmount int,
#Fine int,
#DueDate date,
#AppliedON date,
#FeeMonth varchar(30)
)
AS
--- Variables Using in Loops
DECLARE #LoopCounter INT , #MaxStudentID INT, #StdID INT, #FID INT
-- Setting Counter From the count of students in student table if they are 'Active'
SELECT #LoopCounter = min(AdmissionNumber) , #MaxStudentID = max(AdmissionNumber)
FROM StudentTable
-- WHILE Loop Condition
WHILE(#LoopCounter IS NOT NULL AND #LoopCounter <= #MaxStudentID )
BEGIN
--- SELECT IDs all Active students and matching with counter
SELECT #StdID = AdmissionNumber
FROM StudentTable WHERE AdmissionNumber = #LoopCounter AND Active = 'True'
--- CHECK IF ROW EXITS
SELECT #StdID = AdmissionNumber
FROM FeeAssociationTable
IF EXISTS ( SELECT FeeMonth FROM FeeAssociationTable
WHERE #LoopCounter = AdmissionNumber AND FeeID = #FeeID AND FeeMonth = #FeeMonth)
BEGIN
UPDATE FeeAssociationTable
SET FeeAmount = #FeeAmount, Fine = #Fine , DueDate = #DueDate
WHERE #LoopCounter = AdmissionNumber AND FeeID = #FeeID
AND FeeMonth = #FeeMonth
END
ELSEBEGIN
INSERT FeeAssociationTable
(FeeID, AdmissionNumber, FeeAmount, FeeMonth, DueDate, Fine, AppliedOn, [Status])
VALUES
(#FeeID, #LoopCounter, #FeeAmount, #FeeMonth, #DueDate, #Fine, #AppliedON, 'Pending')
END
SET #LoopCounter = #LoopCounter + 1
END
This is working if the Ids are continuous. What should I do if there is an Id missing or how to skip that specific number which is not present in the studentTable.
Explanation:
The loop take the initial value of min(id) from studentTable set as counter, and final value of max(id).
The loop compares both values id in studentTable and counter of the loop.
Then for each counter student in the table the the fee is assigned.
INSERT FeeAssociationTable
(FeeID, AdmissionNumber, FeeAmount, FeeMonth, DueDate, Fine, AppliedOn, [Status])
VALUES
(#FeeID, #LoopCounter, #FeeAmount, #FeeMonth, #DueDate, #Fine,
The problem is here, while inserting I am using #LoopCounter. Lets say #LoopCounter = 100 but StudentTable is skipping 100 and there is 101 there. The conflict rises. Because the SQL can't find the **100** id in the studentTable.
Thanks in Advance.
As I said in a comment, this whole thing looks like it can be replaced by a MERGE. Don't do things one step at a time when you can tell the server what to do with the entire set of rows.
Something like:
MERGE INTO FeeAssociationTable t
USING (SELECT AdmissionNumber, #FeeID as FeeID, #FeeMonth as FeeMonth FROM StudentTable
WHERE Active = 'True') s
ON t.AdmissionNumber = s.AdmissionNumber AND
t.FeeID = s.FeeID AND
t.FeeMonth = s.FeeMonth
WHEN MATCHED THEN UPDATE SET FeeAmount = #FeeAmount, Fine = #Fine , DueDate = #DueDate
WHEN NOT MATCHED THEN INSERT
(FeeID, AdmissionNumber, FeeAmount, FeeMonth, DueDate, Fine, AppliedOn, [Status])
VALUES
(#FeeID, s.AdmissionNumber, #FeeAmount, #FeeMonth, #DueDate, #Fine, #AppliedON, 'Pending');
Not sure I've got all of the conditions quite right, but you should be able to see what I'm driving at, I hope.
Your actual issue could have been "solved" by replacing:
SET #LoopCounter = #LoopCounter + 1
with:
SELECT #LoopCounter = MIN(AdmissionNumber) FROM StudentTable
WHERE Active = 'True' and AdmissionNumber > #LoopCounter
but don't do that, please.
Man , you should use a For each . For example:
DECLARE yourCursor CURSOR LOCAL STATIC
FOR SELECT AdmissionNumber
FROM StudentTable
OPEN yourCursor
FETCH NEXT FROM yourCursor INTO #StdID
WHILE ##FETCH_STATUS = 0
BEGIN
/*
CHECK IF EXIST FOR UPDATE OR INSERT
*/
FETCH NEXT FROM yourCursor INTO #StdID
END
CLOSE yourCursor
DEALLOCATE yourCursor
GO
This replace your while.

Catching multiple errors in loop SQL query

I have the below insert query which selects records from the OriginalData table where everything is of datatype nvarchar(max) and inserts it into the temp table which has specific column definitions i.e MainAccount is of type INT.
I am doing a row by row insert because if there is a record in OriginalData table where the MainAccount value is 'Test' the it will obviously cause a conversion error and the insert will fail. The begin try block is used to update the table with the error.
However if there are multiple errors on the same row I want to be able to capture them both and not just the first one.
TRUNCATE TABLE [Temp]
DECLARE #RowId INT, #MaxRowId INT
SET #RowId = 1
SELECT #MaxRowId = MAX(RowId)
FROM [Staging].[FactFinancialsCoded_Abbas_InitialValidationTest]
WHILE(#RowId <= #MaxRowId)
BEGIN
BEGIN TRY
INSERT INTO [Temp] (ExtractSource, MainAccount,
RecordLevel1Code, RecordLevel2Code, RecordTypeNo,
TransDate, Amount, PeriodCode, CompanyCode)
SELECT
ExtractSource, MainAccount,
RecordLevel1Code, RecordLevel2Code, RecordTypeNo,
TransDate, Amount, PeriodCode, DataAreaId
FROM
[Staging].[FactFinancialsCoded_Abbas_InitialValidationTest]
WHERE
RowId = #RowId;
PRINT #RowId;
END TRY
BEGIN CATCH
Update [Staging].[FactFinancialsCoded_Abbas_InitialValidationTest]
Set ValidationErrors = ERROR_MESSAGE()
where RowId = #RowId
END CATCH
SET #RowId += 1;
END
Instead of doing it this way, I handle this by using TRY_PARSE() or TRY_CONVERT() on each column that I am converting to a non-string column.
If you then need to store the validation failures in another table, you can make a second pass getting all the rows that have a non-null value in the source table and a null value in the destination table, and insert those rows into your "failed validation" table.

While Loop SAP B1 SQL stored procedure for blocking

I have an issue with my stored procedure SAP B1.
What I'm trying to do here is storing the sum of the quantity, group by the manufacturing order and insert it into the temp table. Then use a while loop to go thru each ID to compare with the user table [#FGTRACKING] and block if
temp.quantity > sum(quantity) in [#FGTracking].
However this is not working, the transaction still passed the stored procedure block. I suspect there is something wrong with my syntax.
IF #transaction_type IN ('A') AND #object_type = '67'
BEGIN
declare #top as int
declare #temp table (id int,quantity int NOT NULL, monum int NOT NULL)
insert into #temp (id, quantity,monum)
select row_number() over (order by (select NULL)), sum(quantity) as quantity, u_shipment_line as monum
from wtr1 t1
where t1.docentry = #list_of_cols_val_tab_del
group by u_shipment_line
set #top = 1
WHILE #top <= (select count(monum) from #temp)
BEGIN
IF EXISTS (select t100.monum from #temp t100
where t100.quantity > (select sum(t111.u_transfer)
from [#FGTRACKING] t111 where t111.u_mo_num = t100.monum
group by t111.u_mo_num) and t100.id = #top)
BEGIN
SELECT #Error = 666, #error_message = 'Over-transfer'
END
ELSE
set #top = #top + 1
END
END
It looks like you're only incrementing your iterator (#top) when you don't encounter your error condition, so if your error condition triggers, you're stuck in an infinite loop.
Get rid of your "else" and always increment #top, or alternatively break out of your while loop when you hit your error condition.
...
ELSE -- Get rid of this else
set #top = #top + 1
...

If else expression compare not working

i want to perform a compare if #accid2 not equal #accid then roll back action, else perform insert.
My result of this trigger is even that is not match but it still insert into my table.
here is my code:
ALTER TRIGGER [dbo].[TG_checkacctypehtl]
ON [dbo].[Accommodation_Hotel] INSTEAD OF INSERT
AS
DECLARE #accid NVARCHAR(50), #accid2 NVARCHAR(50),#hid NVARCHAR(50),#fsp NVARCHAR(50), #fc NVARCHAR(50), #sr NVARCHAR(50);
SELECT #hid = i.hotel_id FROM INSERTED i;
SELECT #fsp = i.facillities_swimming_pool FROM INSERTED i;
SELECT #fc = i.facillities_catering FROM INSERTED i;
SELECT #sr = i.star_rating FROM INSERTED i;
SELECT #accid2 = i.accommodation_id FROM INSERTED i;
SELECT #accid = accommodation_id FROM [dbo].[Accommodation] WHERE accommodation_type= 'hotel' AND accommodation_id=#accid2;
BEGIN
BEGIN TRAN
SET NOCOUNT ON
PRINT #accid2
PRINT #accid
IF(#accid2 != #accid)
BEGIN
RAISERROR('Record Not Inserted, Accommodation ID is not a Hotel Id',16,1); ROLLBACK; END
ElSE BEGIN
INSERT INTO [dbo].[accommodation_hotel] (hotel_id,facillities_swimming_pool,facillities_catering,star_rating,accommodation_id)
VALUES (#hid,#fsp,#fc,#sr,#accid2);COMMIT;
END
END
*print is for check the value i get.
is that my logic error or my syntax error?
I would rewrite the whole trigger something like this...
ALTER TRIGGER [dbo].[TG_checkacctypehtl]
ON [dbo].[Accommodation_Hotel]
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [dbo].[accommodation_hotel] (hotel_id,facillities_swimming_pool,facillities_catering,star_rating,accommodation_id)
SELECT i.hotel_id
,i.facillities_swimming_pool
,i.facillities_catering
,i.star_rating
,i.accommodation_id
FROM inserted i
WHERE EXISTS ( SELECT 1
FROM [dbo].[Accommodation] a
WHERE a.accommodation_type= 'hotel'
AND a.accommodation_id = i.accommodation_id)
IF EXISTS (SELECT 1 FROM inserted i
WHERE NOT EXISTS ( SELECT 1
FROM [dbo].[Accommodation] a
WHERE a.accommodation_type= 'hotel'
AND a.accommodation_id = i.accommodation_id)
)
BEGIN
RAISERROR('Records with invalid Accommodation ID is not a Hotel Id not inserted',16,1);
END
END
Insert the rows with valid accommodation ids and raise an error if there are any rows with invalid Hotel Ids, Also no need for all those variables.
Also triggers are fired for each transaction, not for each row. Your code assume there will only be one rows inserted ever in the table at a time.
Should be IF(#accid2 <> #accid)

loop in sql stored procedure and removing cursors

I have to modify a STORED procedure that is written by someone else.Basically the stored prcoedure uses a cusrsor to fetch the data from the table and then insert that data in another table. While fetching the code form another table, it also gets some distinct columns from another table Below is my code:
Declare data_cursor cursor for
Select emp_no, emp_name, event_date, Test_no, Code, Test_result
From test_table1
ORDER by emp_no
declare
#empNo varchar(100),
#emp_name varchar(2000),
#eventDate varchar(20),
#TestNo varchar(100),
#Code varchar(100),
#TestReuslt varchar(100),
#ProcessName varchar(100),
#FileProcess varchar(200),
#TestProcess varchar(100),
#countA int,
#error_count int
SELECT #ProcessName = (select distinct userID from test_table1)
SELECT #FileProcess = 'EW' + #ProcessName
Select #TestProcess = (Select distinct userID from test_Table1) + 'TXT'
select #countA = 0
BEGIN tran
OPEN data_cursor
fetch data_cursor into
#empNo ,
#emp_name ,
#eventDate ,
#TestNo ,
#Code ,
#TestReuslt
while (##FETCH_STATUS=0)
begin
insert into TESTTable2
(
empNum, empName, eventDate,TestNum, Code, TestResult, Testprocess, ProcessName)
values (#empNo, #emp_name, #eventDate , #TestNo , #Code, #TestReuslt, #TestProcess, #ProcessName)
if # ERROR > 0
begin
select #error_count = #error_count + 1
end
else
set #record_id = ##Identity
if #code like 'D%'
Insert into TESTTable3
(testProcess, FileProcess, empNum)
values (#TestProcess, #FileProcess, #empNo )
if ##error > 0
begin
select #error_count = #error_count + 1
end
set #countA = #countA + 1
fetch data_cursor into
fetch data_cursor into
#empNo ,
#emp_name ,
#eventDate ,
#TestNo ,
#Code ,
#TestReuslt
if # ERROR > 0
BEGIN
select #error_count = #error_count + 1
end
end
if #error_count > 0
begin
rollback tran
end
else
begin /* ##error = 0 */
commit tran
close data_cursor
deallocate data_cursor
Insert into LOG_File
(Name, Count, Processname)
values ('Test1', #CountA,#ProcessName)
Select 'TotalCount' = #CountA
The reason, I have to modify the above STORED proc now is because of some APPLICATION changes, I am getting around 50 distinct userID's from test_table1 so the above subquery(SELECT #ProcessName = (select distinct userID from test_table1) doesn't work. How can I loop through the above stored proc so that each #ProcessName can get inserted in table TESTTable2 so in other words
I want to pass each userId one at a time and insert it in table test_table1 and other subsequent tables. I can declare another cursor to accomplish this, but I was wondering if there is any better way to rewrite this stored proc and not use the cursor at all.
because of my application changes all these three statements above are throwing the error:
SELECT #ProcessName = (select distinct userID from test_table1)
SELECT #FileProcess = 'EW' + #ProcessName
Select #TestProcess = (Select distinct userID from testTable1) + 'TXT'
I am using sql server 2005.
any help will be greatly appreciated.
declare #countA int=0
begin tran
begin try
insert into TESTTable2(empNum, empName, eventDate,TestNum, Code, TestResult, Testprocess, ProcessName)
Select emp_no, emp_name, event_date, Test_no, Code, Test_result,userID+ 'TXT',userID
From test_table1
ORDER by emp_no
SET #CountA=##ROWCOUNT
Insert into TESTTable3(testProcess, FileProcess, empNum)
Select userID+ 'TXT','EW' + userID,emp_no
From test_table1
Where code like 'D%'
ORDER by emp_no
commit tran
Insert into LOG_File(Name, Count, Processname) values ('Test1', #CountA,'#ProcessName')
end try
begin catch
rollback tran
SET #CountA =0
Insert into LOG_File(Name, Count, Processname) values ('Test1', #CountA,'#ProcessName')
SELECT ERROR_NUMBER() AS ErrorNumber,ERROR_MESSAGE() AS ErrorMessage
end catch
Select #CountA [TotalCount]