Return one OUTPUT result from MERGE query - sql

I have a merge query which updates or inserts if no records found. In my results, I have a problem when the record does not exist and it get inserted. The query returns BOTH 'Updated' (as empty) and 'Inserted' (with the proper value).
Any ideas how to avoid return the empty 'Updated' when there are no updates?
ALTER PROCEDURE [dbo].[spInsOrUpdApplicant]
-- Add the parameters for the stored procedure here
#Name nvarchar(50),
#Surname nvarchar(50),
#Position nvarchar(50),
#NationalID int,
#ApplicantID int
AS
BEGIN
SET NOCOUNT ON;
-- Update the row if it exists.
UPDATE tbApplicant
SET Name = #Name, Surname = #Surname, Position = #Position, NationalID = #NationalID
OUTPUT INSERTED.ApplicantID AS 'Result'
WHERE ApplicantID = #ApplicantID;
-- Insert the row if the UPDATE statement failed.
IF (##ROWCOUNT = 0 )
BEGIN
INSERT INTO tbApplicant (Name, Surname, Position, NationalID)
OUTPUT INSERTED.ApplicantID AS 'Result'
VALUES (#Name, #Surname, #Position, #NationalID)
END
END;

It seems that the 'output' always fires even if no actual rows were updated. You can see the same behavior in triggers. You might want to consider doing the following:
ALTER PROCEDURE [dbo].[spInsOrUpdApplicant]
-- Add the parameters for the stored procedure here
#Name nvarchar(50),
#Surname nvarchar(50),
#Position nvarchar(50),
#NationalID int,
#ApplicantID int
AS
BEGIN
SET NOCOUNT ON;
-- Check if the row exists.
IF EXISTS (SELECT 1 FROM tbApplicant WHERE ApplicantID = #ApplicantID) BEGIN
-- update if the row exists.
UPDATE tbApplicant
SET Name = #Name, Surname = #Surname, Position = #Position, NationalID = #NationalID
OUTPUT INSERTED.ApplicantID AS 'Result'
WHERE ApplicantID = #ApplicantID;
END
ELSE BEGIN
-- Else Insert.
INSERT INTO tbApplicant (Name, Surname, Position, NationalID)
OUTPUT INSERTED.ApplicantID AS 'Result'
VALUES (#Name, #Surname, #Position, #NationalID)
END
END;

I do something very similar.
Inside my stored procedure, I have this:
DECLARE #mergeResults TABLE (mergeAction varchar(10), tableName varchar(50));
OUTPUT $action, 'Table Name' INTO #mergeResults;
Can you insert into the table variable and then decide how you want to move the data based on what you see?
You mentioned you have a merge query but you aren't using a merge - you're using more of an "upsert".
Merge T-SQL: http://msdn.microsoft.com/en-us/library/bb510625.aspx

Related

SQL Server stored procedure: verify CRUD operation success/failure using output variable

I am trying to create a SQL Server stored procedure to handle updates to a table using some dynamic SQL. The table name required for the update is stored in a table that correlates a table id to a category id. Once the table name is retrieved and the table id is not null, I update the table using a dynamic SQL query as shown below:
CREATE PROCEDURE [dbo].[SP_EBS_CustomForms_SetCategoryData]
(#flag int output,
#cat_id int,
#sort int,
#value varchar(50),
#active int,
#enum int)
AS
BEGIN
DECLARE #tbl as varchar(50)
DECLARE #tbl_id as int
DECLARE #sql nvarchar(max)
BEGIN TRY
SET #tbl_id = (SELECT [tbl_id]
FROM [demodata].[dbo].[ebscustomforms_cattable]
WHERE cat_id = #cat_id)
IF #tbl_id IS NOT NULL
BEGIN
SET #tbl = (SELECT table_name
FROM ebscustomforms_enumtable
WHERE tbl_id = #tbl_id)
SET #sql = 'UPDATE ' + #tbl + ' SET [sort_order] = #sort, [value] = #value, [active] = #active WHERE [enum_id] = #enum'
EXECUTE sp_executesql #sql, N'#sort int, #value varchar(50), #active int, #enum int', #sort, #value, #active, #enum
SET #flag = 0
RETURN #flag
END
END TRY
BEGIN CATCH
IF ##ERROR <> 0
BEGIN
SET #flag = 1;
RETURN #flag
END
END CATCH
END
I want this stored procedure to return an int value indicating whether the stored procedure was successful (0) or failed (1) updating the table.
Points of error are as follows:
#tbl_id variable is null
#tbl is either null or an empty varchar
The table to be updated does not have a record where [enum_id] = #enum
I have noticed that when I try to update a record that does not exist, the procedure seems to return as successful i.e. #flag = 0. However, I would imagine that an error should be thrown because the record does not exist.

SQL Server Trigger containing one or two cursors

I am trying to create a cursor, or cursors, inside of a trigger. What I need to do is when one field in a table is updated, I have to have one cursor or two cursors iterate through and record all of the fields in a table and insert the old and new values into a table.
Here is the code I currently have. This code iterates through the new values in the inserted table correctly, but does not iterate through the old values, in the deleted table.
ALTER TRIGGER [dbo].[Audit_Emp_Trigger]
ON [dbo].[EMPLOYEE]
AFTER UPDATE, DELETE
AS
BEGIN
--Set the fields that we will need in this trigger
DECLARE #OldLName NVARCHAR(50);
DECLARE #NewLName NVARCHAR(50);
DECLARE #OldSSN INT;
DECLARE #NewSSN INT;
DECLARE #OldDno INT;
DECLARE #NewDno INT;
DECLARE #Fname NVARCHAR(50);
DECLARE #Mname NVARCHAR(50);
DECLARE #BDate DATE;
DECLARE #Address NVARCHAR(100);
DECLARE #Sex CHAR(1);
DECLARE #Salary INT;
DECLARE #SuperSSN INT;
--Only execute the trigger if the Dno field was updated or deleted
IF UPDATE(Dno)
BEGIN
--If this is an insert operation, we will be inserting a new Dno value
SELECT #OldLName = D.LName FROM deleted D
SELECT #OldSSN = D.Ssn FROM deleted D
SELECT #OldDno = D.Dno FROM deleted D
DECLARE InsertCursor CURSOR FOR SELECT Fname, Minit, Lname, Ssn, Bdate, Address, Sex, Salary, Super_ssn, Dno FROM inserted
OPEN InsertCursor
FETCH NEXT FROM InsertCursor INTO #Fname, #Mname, #NewLName, #NewSSN, #BDate, #Address, #Sex, #Salary, #SuperSSN, #NewDno
WHILE ##FETCH_STATUS = 0
BEGIN
--If the Audit_Emp_Record table does not exist already, we need to create it
IF OBJECT_ID('dbo.Audit_Emp_Record') IS NULL
BEGIN
--Table does not exist in database, so create table
CREATE TABLE Audit_Emp_Record
(
date_of_change smalldatetime,
old_Lname varchar (50),
new_Lname varchar (50),
old_ssn int,
new_ssn int,
old_dno int,
new_dno int
);
--Once table is created, insert the values of the update operation into the table
INSERT INTO Audit_Emp_Record(date_of_change, old_Lname, new_Lname, old_ssn, new_ssn, old_dno, new_dno) VALUES(GETDATE(), #OldLName, #NewLName, #OldSSN, #NewSSN, #OldDno, #NewDno)
END
ELSE
BEGIN
--The table already exists, so simply insert the new values of the update operation into the table
INSERT INTO Audit_Emp_Record(date_of_change, old_Lname, new_Lname, old_ssn, new_ssn, old_dno, new_dno) VALUES(GETDATE(), #OldLName, #NewLName, #OldSSN, #NewSSN, #OldDno, #NewDno)
END
FETCH NEXT FROM InsertCursor INTO #Fname, #Mname, #NewLName, #NewSSN, #BDate, #Address, #Sex, #Salary, #SuperSSN, #NewDno
END
END
END

getting the last inserted id from previous insert statement

I am having a stored procedure with two insert statement, where I want to insert the ID of the first insert statement into the second one.
CREATE PROC [dbo].[Log_Action]
#action_description VARCHAR(MAX),
#creator_id INT,
#entity VARCHAR(50),
#entity_identifier UNIQUEIDENTIFIER
AS
BEGIN
DECLARE #return_value BIT;
BEGIN TRY
INSERT INTO Action_Lookup (action_description)
VALUES (#action_description);
INSERT INTO Audit ([user_id], action_id, CREATED, [guid], entity, entity_identifier)
VALUES (#creator_id, SCOPE_IDENTITY(), GETDATE(), NEWID(), #entity, #entity_identifier);
SET #return_value = 1;
RETURN #return_value;
END TRY
BEGIN CATCH
SET #return_value = 0;
RETURN #return_value;
END CATCH
END
the problem that SCOPE_IDENTITY() returns null, I also tried ##IDENTITY and IDENT_CURRENT but non works.
Try output clause:
CREATE PROC [dbo].[Log_Action]
#action_description VARCHAR(MAX),
#creator_id INT,
#entity varchar(50),
#entity_identifier uniqueidentifier
AS
BEGIN
DECLARE #return_value bit;
BEGIN TRY
INSERT INTO Action_Lookup (action_description)
OUTPUT
#creator_id,
inserted.[id], -- in [] there should be actual name of identity column
GETDATE(),
NEWID(),
#entity,
#entity_identifier
INTO Audit ([user_id], action_id, created, [guid], entity, entity_identifier)
VALUES (#action_description);
set #return_value = 1;
return #return_value;
END TRY
BEGIN CATCH
set #return_value = 0;
return #return_value;
END CATCH
END

trigger at particular column with condition

I want to check a Column value when update.If its match insert into another table.
My Tables:
My trigger:
CREATE TRIGGER tr_test
ON test1
FOR UPDATE
AS
SET nocount ON
IF ( Update(sname) )
DECLARE #Name NVARCHAR
DECLARE #id INT
SET #id=##IDENTITY
SET #Name=(SELECT sname
FROM test1
WHERE id = #id)
IF( #Name = 'Paras' )
BEGIN
INSERT INTO test2
(loginfo)
VALUES ('success')
END
And my update query is:
update Test1 set Sname='Paras' where ID=1
When I run this update query Nothing is happen.Test2 table is empty.I think problem is ##IDENTITY but not sure.Thanks.
Try this:
CREATE TRIGGER tr_test
ON test1
FOR UPDATE
AS
SET nocount ON
IF ( Update(sname) )
DECLARE #Name NVARCHAR
DECLARE #id INT
SET #id=(select id from inserted)
SET #Name=(SELECT sname
FROM inserted
WHERE id = #id)
IF( #Name = 'Paras' )
BEGIN
INSERT INTO test2
(loginfo)
VALUES ('success')
END
But it's better to do this, an update can update many rows, the above will fail if UPDATE matches many rows, use EXISTS:
CREATE TRIGGER tr_test
ON test1
FOR UPDATE
AS
SET nocount ON
IF( EXISTS(select * From inserted where sname = 'Paras' ) )
BEGIN
INSERT INTO test2
(loginfo)
VALUES ('success')
END
inserted table is the name of the table where the UPDATE's new values goes, deleted table is the name of the table where UPDATE's old values goes

Stored Procedure OutPut Parameters

i need to write a stored procedure which will return a string.logic is
when user try to insert a new record i need to check whether that record already exist.if exist need to return msg "Record exist" else return "Inserted"
following is what i have done for the moment and i'm stuck here.can some one help me to complete the procedure
CREATE PROCEDURE [dbo].[spInsetPurpose]
#Purpose VARCHAR(500),
#Type VARCHAR(6),
#Result VARCHAR(10)= NULL OUTPUT
AS
BEGIN
Declare #Position VARCHAR(20)
DECLARE #TempTable TABLE (Purpose VARCHAR(500))
INSERT INTO #TempTable
SELECT Purpose FROM tblPurpose WHERE Purpose=#Purpose
INSERT INTO tblPurpose(Purpose,[Type]) VALUES(#Purpose,#Type)
END
To check if the row already exists you can do
If Exists (Select Top 1 1 from tblPurpose where Purpose = #Purpose and [Type] = #Type)
Begin
Insert Into tblPurpose
(Purpose, [Type])
Select
#Purpose, #Type
SET #Result = 'Inserted'
End
Else
Begin
SET #Result = 'Record exists'
End