I have created this stored procedure
CREATE PROCEDURE AddNewMaterialType4
(#category varchar(15),
#materialType varchar(50),
#userID varchar(15),
#result1 varchar(15) OUTPUT)
AS
DECLARE #count1 INT;
SET #count1 = 0;
SELECT #count1 = COUNT(*)
FROM [vmsMaterialType]
WHERE category = #category
AND materialType = #materialType;
IF #count1 = 0
BEGIN
SET NOCOUNT ON;
INSERT INTO [vmsMaterialType] ([category], [materialType],[createdBy])
VALUES (#category, #materialType, #userID);
SET #result1 = 'Success';
END
ELSE
SET #result1 = 'Fail';
GO
When I execute the following I am not getting the result I expect (Success/Fail) instead its giving me the output what ever I declare result1 as.
declare
#result1 varchar(15) = '1';
begin
execute AddNewMaterialType4 #category = 'Beef', #materialtYPE = '25 Trim', #userID = 'JJ', #result1 = #result1;
print #result1;
end;
In your execute AddNewMaterialType4 call, you have to explicitly state that #result1 is an output variable. Try this instead:
declare
#result1 varchar(15) = '1';
begin
execute AddNewMaterialType4 #category = 'Beef', #materialtYPE = '25 Trim', #userID = 'JJ', #result1 = #result1 output;
print #result1;
end;
Related
I am working on an Enterprise Database Management course project and cannot seem to get my error handling to perform correctly on a transaction. My instructor advised me to take a look at the error "Msg 266, Level 16, State 2, Procedure pInsertVolunteer, Line 28
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. " but I have not yet found any solutions that are working for this transaction.
CREATE PROCEDURE [dbo].[pInsertVolunteer]
#LastName varchar(255),
#FirstName varchar(255),
#DateOfBirth date,
#Note varchar(MAX),
#ModifiedBy nvarchar(50),
#Success bit Output,
#ErrorStatus Nvarchar(50) Output
AS
SET NOCOUNT ON;
SET XACT_ABORT ON;
BEGIN
DECLARE
#TempVolunteerID int,
#VolunteerID int,
#VolunteerPersonID int;
SET #TempVolunteerID = 0;
SET #Success = 0;
SET #ErrorStatus = '';
END
BEGIN TRY
BEGIN TRANSACTION;
SELECT #TempVolunteerID = VolunteerID
FROM Volunteer.VolunteerInfo
WHERE FirstName = #FirstName AND LastName = #LastName AND DateOfBirth = #DateOfBirth
If #TempVolunteerID <>0
BEGIN
SELECT #ErrorStatus = 'Person Already Exists';
SET #Success = 0;
RAISERROR (#ErrorStatus, 16,1);
END
IF ##ERROR <>0
BEGIN
SELECT #ErrorStatus = CONVERT (nvarchar(50),##ERROR) + '-1000';
SET #Success = 0;
RAISERROR(#ErrorStatus, 16,1);
END
INSERT INTO Volunteer.VolunteerInfo (LastName, FirstName, DateOfBirth)
values (#LastName, #FirstName, #DateofBirth)
SET #Success = 1;
SET #ErrorStatus = 0;
SELECT #VolunteerPersonID = VolunteerID
FROM Volunteer.VolunteerInfo
If #VolunteerPersonID = 0 OR #VolunteerPersonID IS NULL
BEGIN
SET #Success =0;
SET #ErrorStatus = '8008: PersonID must be valid';
RAISERROR(#ErrorStatus,16,1);
END
Insert into Volunteer.VolunteerNotes (Note,ModifiedDate, ModifiedBy)
Values (#Note,SYSDATETIME(), #ModifiedBy)
SET #VolunteerPersonID = ##IDENTITY;
SET #Success = 1;
SET #ErrorStatus = 0;
SET NOCOUNT OFF;
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
BEGIN
SELECT #ErrorStatus = #ErrorStatus + CONVERT (nvarchar(50), ##ERROR);
END
SET #Success = 0;
SET #ErrorStatus = #ErrorStatus + '-1001';
RAISERROR(#ErrorStatus, 15,1)
ROLLBACK TRANSACTION;
END CATCH
GO
Any help would be greatly appreciated.
Thank you!
Please try this way :
CREATE PROCEDURE [dbo].[pInsertVolunteer] #LastName VARCHAR(255),
#FirstName VARCHAR(255),
#DateOfBirth DATE,
#Note VARCHAR(MAX),
#ModifiedBy NVARCHAR(50),
#Success BIT OUTPUT,
#ErrorStatus NVARCHAR(50) OUTPUT
AS
-- settings
SET NOCOUNT ON;
SET XACT_ABORT ON;
-- variables
DECLARE #TempVolunteerID INT = 0, #VolunteerID INT, #VolunteerPersonID INT;
SET #Success = 0;
SET #ErrorStatus = '';
-- controled transaction
BEGIN TRY
BEGIN TRANSACTION;
SELECT #TempVolunteerID = VolunteerID
FROM Volunteer.VolunteerInfo
WHERE FirstName = #FirstName
AND LastName = #LastName
AND DateOfBirth = #DateOfBirth;
IF #TempVolunteerID <> 0
BEGIN
SELECT #ErrorStatus = 'Person Already Exists';
SET #Success = 0;
RAISERROR(#ErrorStatus, 16, 1);
END;
IF ##ERROR <> 0
BEGIN
SELECT #ErrorStatus = CONVERT(NVARCHAR(50), ##ERROR) + '-1000';
SET #Success = 0;
RAISERROR(#ErrorStatus, 16, 1);
END;
INSERT INTO Volunteer.VolunteerInfo
(LastName,
FirstName,
DateOfBirth
)
VALUES
(#LastName,
#FirstName,
#DateofBirth
);
SET #Success = 1;
SET #ErrorStatus = 0;
SELECT #VolunteerPersonID = VolunteerID
FROM Volunteer.VolunteerInfo;
IF #VolunteerPersonID = 0
OR #VolunteerPersonID IS NULL
BEGIN
SET #Success = 0;
SET #ErrorStatus = '8008: PersonID must be valid';
RAISERROR(#ErrorStatus, 16, 1);
END;
INSERT INTO Volunteer.VolunteerNotes
(Note,
ModifiedDate,
ModifiedBy
)
VALUES
(#Note,
SYSDATETIME(),
#ModifiedBy
);
SET #VolunteerPersonID = ##IDENTITY;
SET #Success = 1;
SET #ErrorStatus = 0;
SET NOCOUNT OFF;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0
BEGIN
ROLLBACK;
SELECT #ErrorStatus = #ErrorStatus + CONVERT(NVARCHAR(50), ERROR_MESSAGE());
END;
SET #Success = 0;
SET #ErrorStatus = #ErrorStatus + '-1001';
RAISERROR(#ErrorStatus, 15, 1);
END CATCH;
GO
I have a large stored procedure which utilises a cursor. I want to put each instance of the cursor processing into a transaction, with a try-catch on the one insert, which on failure would terminate that transaction, back any inserts it did and then move to the next cursor instance. However, I am struggling with structuring this.
An example of what it looks like in brief is below. Basically I am trying to structure the try-catch for the patient insert to rollback the transaction and go onto the next cursor value when the patient insert fails.
Thanks
ALTER procedure [dbo].[Import_Archive_Record]
#PatientNumber varchar(10),
#PracticeId int
as
begin
DECLARE csr1 CURSOR for
select PatientNumber from ArchiveFull.dbo.ArchiveMasters where imported = 0 and PracticeId =
#PracticeId and PatientNumber = #PatientNumber
open csr1
fetch next from csr1 into #PatNo
while ##FETCH_STATUS = 0
begin
insert into Member....
select #memberId = SCOPE_IDENTITY()
print 'new member ' + cast(#memberId as varchar(10))
--insert patient
BEGIN TRY
select #initials = PatientInitials ,#surname = PatientSurname ,#name = PatientFirstname,
#DateOfBirth = DOBStr,#PatientCentury = DOBCen
from ArchiveFull.dbo.ArchiveMasters
where ArchiveFull.dbo.ArchiveMasters.PatientNumber = #PatNo
and imported = 0
and PracticeId = #PracticeId
set #patientID = null
select #patientID = id from Patient
where Initials = #initials
and Surname = #surname
and Name = #name
and MemberId = #memberId
print 'patientid ' + cast(#patientID as varchar(10))
set #DOB = dbo.getVisitdate(#PatientCentury,#DateOfBirth)
if #patientID is null
begin
insert into Patient(Name, Surname,Initials,MemberId,PostalSuburb,PostalCity,PostalCode,PostBox,Gender, DateofBirth,IDNumber,DependentCode,RelationToMember,AlternativesRelation,EMailAddress,CellPhone,Title)
select PatientFirstname,PatientSurname, coalesce(PatientInitials,'.'),#memberId,PatientAddress1, PatientAddress2, PatientAddress3,PatientAddress4,Gender,#DOB,PatientIDNumber,1,1,0,PatientEmail, CellNumber,PatientTitle
from ArchiveFull.dbo.ArchiveMasters
where PatientNumber = #PatNo
and imported = 0
END TRY
BEGIN CATCH
END CATCH
select #patientID = SCOPE_IDENTITY()
print 'new patientid ' + cast(#patientID as varchar(10))
end
set #BranchId = (select top 1 id from Branch where practiceid = #practiceId and ModalityRooms like concat('%', #BranchCode,'%'))
set #visitId = null
select #visitId = id from Visit
where BookingNumber = #PatNo
and BranchId = #BranchId
if #visitId is null
begin
declare #visitDate datetime
declare #century int
declare #date int
declare #DoctorCode nvarchar (max)
declare #DoctorSurname nvarchar (max)
declare #wca bit
select #century = Century, #date = ExamDateStr, #DoctorCode = RefDocCode, #DoctorSurname = RefDoc, #wca=WCA
from ArchiveFull.dbo.ArchiveMasters
where ArchiveFull.dbo.ArchiveMasters.PatientNumber = #PatNo
and imported = 0
and PracticeId = #PracticeId
update testlist
set century = #century, examdate = #date
where patno = #PatNo
set #visitDate = isnull(dbo.getVisitdate(#century,#date),'19000101')
set #DoctorId = null
set #DoctorId = dbo.getDoctorIdRadmin(#DoctorCode,#practiceId)
insert into Visit(Date,EndMonth, EndYear,NewBorn,HospitalClaim,WCA,WorkersComp,RAF,RoadAccidentFund,Examined,Booking,BookingNumber,PatientId,Notes,PreAuthorise,PreAuthNumber,BranchId,DoctorId, Receipted, ArchiveId)
select #visitDate, MONTH(#visitDate), YEAR(#visitdate) ,0,0,0,'',0,'',1,1,#PatNo,#patientID,'',0,AUTHNO,#BranchId,#DoctorId, 0, #archiveid
from ArchiveFull.dbo.ArchiveMasters
where ArchiveFull.dbo.ArchiveMasters.PatientNumber = #PatNo
and imported = 0
and PracticeId = #PracticeId
fetch next from csr1 into #PatNo
end
close csr1
deallocate csr1
CREATE PROC Valtest( #job_id INT)
AS
BEGIN
DECLARE #count INT
DECLARE #response VARCHAR(50)
SELECT #count=Count(0)
FROM employee
WHERE job_id=#job_id
IF(#count = 0 )
SET #response='No';
ELSE
SET #response='Yes';
ENDDECLARE #response VARCHAR(50)`enter code here`EXEC #response
=Valtest 5SELECT #response
--exec test 200
Proper way:
CREATE PROC Valtest( #job_id INT)
AS
BEGIN
IF EXISTS(SELECT 1 FROM employee WHERE job_id=#job_id)
SELECT 'Yes';
ELSE
SELECT 'No';
END
Return statement from stored procedure indicates the status - 0 procedure was run successfully. If you need to return value you should use OUTPUT parameter;
CREATE PROC Valtest( #job_id INT, #result VARCHAR(100) OUTPUT)
AS
BEGIN
IF EXISTS(SELECT 1 FROM employee WHERE job_id=#job_id)
SET #result = 'Yes';
ELSE
SET #result = 'No';
END;
DECLARE #r NVARCHAR(100);
EXEC Valtest #job_id = 200, #result = #r OUTPUT;
SELECT #r;
I want to return the ERROR_MESSAGE() in a variable, but this is not working because is like raising the error but I don't want it like that. I want to receive the return value (0 ok, 1 error), plus the id of the insert in the variable #Id and the error msg in this variable #ErrorMsg if there is an error
Here is the code:
CREATE PROCEDURE [cimpl].[TestInsert]
(
#TestId INT,
#Name NVARCHAR(50),
#Id INT OUTPUT,
#ErrorMsg NVARCHAR(4000) = NULL OUTPUT
)
AS
BEGIN
DECLARE #ReturnVal int
SET NOCOUNT ON;
SET #ReturnVal = 0;
SET #ErrorMsg = '';
BEGIN TRY
-- Insert statement
INSERT [dbo].[Test]
(
[TestId],
[Name]
)
VALUES (
#TestId,
#Name,
)
SET #Id = SCOPE_IDENTITY();
END TRY
BEGIN CATCH
SET #ReturnVal = 1;
SET #ErrorMsg = ERROR_MESSAGE();
END CATCH
RETURN #ReturnVal;
END
Here is the call:
DECLARE #IdIns INT
DECLARE #ErrorM NVARCHAR(4000)
DECLARE #ReturnValue INT = 0
EXEC #ReturnValue =
[cimpl].[TransactInsert]
#TestId= 'ee', --I'm forcing the error
#Name = 'A',
#Id = #IdIns OUTPUT,
#ErrorMsg = #ErrorM OUTPUT
SELECT #ErrorM
SELECT #ReturnValue
SELECT #IdIns
The code in your stored proc should work as expected. The problem is your test is throwing an error before the proc even runs since you are attempting to assign a char value to an integer.
In your test code:
#TestId= 'ee', --I'm forcing the error
This throws an error at parse-and-compile time since #TestId is defined as an INT, however ee is a CHAR(2) value that cannot be coalesced into a number.
Background:
I have a series of stored procedures that inserts one new record into 5 tables (all have a one-to-one relationship). Each stored procedure creates a unique ID for the related table. The last stored procedure adds all of those unique IDs into the last table (to allow for an INNER JOIN to retrieve all information across the individual tables).
I have created an additional stored procedure (let's call it spWrapper) that calls the 4 individual stored procedures (mentioned above). I would like to use the spWrapper to both insert and update a record. The current (insert) spWrapper only inserts a record; the 5 unique IDs are declared as OUTPUT parameters. My T-SQL knowledge is still basic and I am not sure how OUTPUT parameters affect stored procedures.
The current spWrapper code (shortened example):
ALTER PROCEDURE [dbo].[spWrapper]
-- Return values
#idAddress INT = NULL OUTPUT,
#idDetermination INT = NULL OUTPUT,
#idLegalDescription INT = NULL OUTPUT,
#idAddresses_LegalDescriptions_Determinations INT = NULL OUTPUT,
#idLOMC INT = NULL OUTPUT,
-- [Table#1] parameters
#Street VARCHAR(50) = NULL,
#City VARCHAR(50) = NULL,
#State VARCHAR(2) = NULL,
#ZipCode5 VARCHAR(5) = NULL,
#ZipCode4 VARCHAR(4) = NULL,
#GISCode VARCHAR(15) = NULL
AS
SET NOCOUNT OFF
SET ROWCOUNT 0
-- =================================
-- Declare and initialize variables
-- =================================
DECLARE #Error INT,
#RC INT,
#Trancount INT,
#Message VARCHAR(255)
SELECT #Error = 0,
#RC = 0,
#Trancount = ##TRANCOUNT,
#Message = NULL
-- ==========================================
-- Insert record into [Table#1]
-- ==========================================
IF #idAddress IS NULL
BEGIN
IF #Trancount = 0 BEGIN TRANSACTION
EXEC #RC = [spTable#1]
#idLogin = #idLogin,
#idAddress = #idAddress,
#Street = #Street,
#State = #State,
#City = #City,
#ZipCode5 = #ZipCode5,
#ZipCode4 = #ZipCode4,
#GISCode = #GISCode
SELECT #Error = ##ERROR
IF #RC <> 0 OR #Error <> 0
BEGIN
IF #Trancount = 0 ROLLBACK TRANSACTION
SELECT #Message = 'dbo.spWrapper: Error inserting record into [Table#1]'
GOTO lbl_abort
END
END
IF #Trancount = 0 COMMIT TRANSACTION
The current spTable#1 code
ALTER PROCEDURE [spTable#1]
#idLogin INT,
#idAddress INT = NULL OUTPUT,
#Street VARCHAR(50),
#State CHAR(2),
#City VARCHAR(50),
#ZipCode5 CHAR(5),
#ZipCode4 CHAR(4),
#GisCode VARCHAR(15)
IF #TranCount = 0 BEGIN TRANSACTION
IF #idAddress IS NULL
BEGIN
INSERT [dbo].[Table#1]
(Street,
[State],
City,
ZipCode5,
ZipCode4,
GisCode,
InsertedidLogin,
InsertedDate)
VALUES
(#Street,
#State,
#City,
#ZipCode5,
#ZipCode4,
#GisCode,
#idLogin,
GETDATE())
SELECT #Error = ##ERROR,
#RC = ##ROWCOUNT,
#idAddress = SCOPE_IDENTITY()
IF #Error <> 0 OR #RC <> 1
BEGIN
IF #TranCount = 0 ROLLBACK TRANSACTION
SELECT #Message = 'spTable#1: Error inserting record into [Table#1]'
GOTO lbl_abort
END
END
My main question:
With the unique ID set as an OUTPUT parameter, can I insert an existing ID to call an UPDATE portion of spTable#1 (and subsequently spWrapper)? OR can I declare those unique IDs (ie: not as an OUTPUT parameter)?
Proposed change
CREATE PROCEDURE [dbo].[spWrapper]
#idLOMC INT = NULL
DECLARE #idAddress INT,
#idLegalDescription INT,
#idDetermination INT,
#idCommunity INT,
#idFirm INT,
#idCounty INT,
#idFloodZone INT,
#Error INT,
#RC INT,
#Trancount INT,
#Message VARCHAR(255)
SELECT #idAddress = NULL,
#idLegalDescription = NULL,
#idDetermination = NULL,
#Error = 0,
#RC = 0,
#Trancount = ##TRANCOUNT,
#Message = NULL
/* Lookup idAddress, idLegalDescription, idDetermination */
IF #idLOMC IS NOT NULL
BEGIN
SELECT #idAddress = A.idAddress, #idLegalDescription = LD.idLegalDescription, #idDetermination = D.idDetermination
FROM [Table#2] L
INNER JOIN [Table#5] ALD
ON L.idAddresses_LegalDescriptions_Determinations = ALD.idAddresses_LegalDescriptions_Determinations
INNER JOIN [Table#1] A
ON ALD.idAddress = A.idAddress
INNER JOIN [Table#3] LD
ON ALD.idLegalDescription = LD.idLegalDescription
INNER JOIN [Table#4] D
ON ALD.idDetermination = D.idDetermination
WHERE L.idLOMC = #idLOMC
IF ##ROWCOUNT = 0
BEGIN
SELECT #Message = 'dbo.spWrapper: Invalid idLOMC'
GOTO lbl_abort
END
END
/* Insert record into [Table#1] */
IF #idAddress IS NULL
BEGIN
IF #Trancount = 0 BEGIN TRANSACTION
EXEC #RC = [spTable#1]
#idLogin = #idLogin,
#idAddress = #idAddress OUTPUT,
#Street = #Street,
#State = #State,
#City = #City,
#ZipCode5 = #ZipCode5,
#ZipCode4 = #ZipCode4,
#GisCode = #GisCode
SELECT #Error = ##ERROR
IF #RC <> 0 OR #Error <> 0
BEGIN
IF #Trancount = 0 ROLLBACK TRANSACTION
SELECT #Message = 'spWrapper: Error inserting record into [Table#1]'
GOTO lbl_abort
END
END
/* Update record into [Table#1] */
ELSE
BEGIN
IF #Trancount = 0 BEGIN TRANSACTION
EXEC #RC = [spTable#1]
#idLogin = #idLogin,
#idAddress = #idAddress,
#Street = #Street,
#State = #State,
#City = #City,
#ZipCode5 = #ZipCode5,
#ZipCode4 = #ZipCode4,
#GisCode = #GisCode
SELECT #Error = ##ERROR
IF #RC <> 0 OR #Error <> 0
BEGIN
IF #Trancount = 0 ROLLBACK TRANSACTION
SELECT #Message = 'spWrapper: Error updating record in [TspTable#1]'
GOTO lbl_abort
END
END