I have a merge statement that should update or insert a single record always. I want to remember the ID of that statement in a variable. It looks like this:
DECLARE #int int
MERGE dbo.table AS A
USING (SELECT 'stringtomatch' AS string) AS B ON B.string= A.string
WHEN MATCHED THEN
UPDATE SET somecolumn = 'something'
WHEN NOT MATCHED THEN
INSERT
VALUES ('stringtomatch',
'something')
OUTPUT #int = inserted.ID;
Now this doesen't work because you can't set #int in the output clause this way. I know I could create a temptable and use INTO #temptable in the output. But since I know it's always a single record I want to have the ID in a INT variable.
Is this even possible? Or am I forced to use a table variable.
How?
No, you have to use a table variable with OUTPUT
However, you can do this...
...
WHEN MATCHED THEN
UPDATE
SET
#int = ID,
somecolumn = 'something'
WHEN NOT MATCHED THEN
INSERT
VALUES ('stringtomatch',
'something');
SET #int = ISNULL(#int, SCOPE_IDENTITY());
The "assign in UPDATE" has been a valid syntax for SQL Server for a long time. See MERGE on MSDN too. Both say this:
...<set_clause>::=
SET
...
#variable=expression
Related
I have a table in DB where some records exist.
When I add a new record I need to check by column "Name" if the record exists in DB. If such a record does not exist - then add it, if exists - then update. I'm trying like this:
USE [TestDB]
GO
DECLARE #daily nvarchar = 'DailySummaryEmailProcessor'
IF NOT EXISTS ( SELECT *
FROM [dbo].Crons
WHERE name = #daily)
BEGIN
INSERT INTO [dbo].Crons (CronJobID, Name, Description)
VALUES()
END
ELSE
BEGIN
UPDATE [dbo].Crons
SET
WHERE
END
MERGE should fit your requirements MERGE (Transact-SQL):
MERGE Crons AS target
USING (SELECT #Name) AS source (Name)
ON (target.Name = source.Name)
WHEN MATCHED THEN
UPDATE SET target.Name = source.Name
WHEN NOT MATCHED
INSERT INTO Crons (Name) VALUES (source.Name)
OUTPUT $action, deleted.Name, inserted.Name
the issue is you never declare the size of the variable #dialy
try this and see what do you get
DECLARE #daily nvarchar = 'DailySummaryEmailProcessor'
SELECT #daily
Looks like you need to do INSERT .. UPDATE.. check out MERGE statement
https://learn.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql?view=sql-server-2017
EDIT:
Oh.. you have MySQL there in the tag. My answer is specifically on SQL Server.
I have this as the first part of a stored procedure:
DECLARE #_id as int
if exists(select 1 from JTrack_Visitors WHERE cookie = #cookie)
begin
UPDATE JTrack_Visitors
SET LastSeen = #_now
WHERE cookie = #cookie
end
else
begin
INSERT INTO JTrack_Visitors(Cookie, CreatedOn, LastSeen)
VALUES (#cookie, #_now, #_now)
end
How can I set #_id to be the identity of the row either being inserted or updated? I need that value to use later in the stored procedure.
Thanks.
You can make use of OUTPUT clause in your both statements, in either case populate a table variable and later retrieve value from that table variable.
DECLARE #_id as int;
DECLARE #ID_Table TABLE(ID INT);
IF EXISTS (select 1 from JTrack_Visitors WHERE cookie = #cookie)
BEGIN
UPDATE JTrack_Visitors
SET LastSeen = #_now
OUTPUT inserted.ID INTO #ID_Table(ID)
WHERE cookie = #cookie
END
ELSE
BEGIN
INSERT INTO JTrack_Visitors(Cookie,CreatedOn,LastSeen)
OUTPUT inserted.ID INTO #ID_Table(ID)
VALUES (#cookie,#_now,#_now)
END
SELECT #_id = ID FROM #ID_Table;
Depending on the SQL Server version you're using you could use the MERGE statement including the OUTPUT clause to get the values you're looking for.
This would also eliminate the need to check for existence and either update or insert.
I have a stored proc that has a merge .. into statement. I am trying to get the value of the primary key out of the stored proc.
SET #NewCompanyID = #CompanyID
....
merge company as c
using ( select #CompanyID) as compAlt (company_id )
on compAlt.company_id = c.company_id
when matched
then
update set ....
when not matched
then
insert ... ;
SET #NewCompanyID = ##identity;
If the merge statement runs the update, i want to set #NewCompanyID to whatever value was passed into the stored proc (#CompanyID). If the insert statement was executed, then I want to pass the ##identity. How do I do this?
I added before merge into
DECLARE #SummaryOfChanges TABLE(Change VARCHAR(20));
then
OUTPUT $action INTO #SummaryOfChanges;
SELECT #Change = Change
FROM #SummaryOfChanges; /* there is always one update or insert */
IF #Change = 'INSERT'
BEGIN
....
END
This worked fine.
how to update with a new variable
let's say I wanted to do the following
update T
set T.property1 = (declare #temp varch(20)
#temp = 'testing')
from #temp_table_name T
is this possible. I need to update a table but the new element is the end result of a series of complicated statements and it would be a lot easier to define some variables along the way to handle intermediate outputs. What is the correct syntax for what I'm trying to do above because it's not working
Is something like this what you're looking for?
DECLARE #temp varchar(20)
SET #temp = 'testing, or the result of a query maybe?'
UPDATE T SET T.property1 = #temp
FROM #temp_table_name T
WHERE 1 = 1
Move all of those statements into a scalar valued user-defined function and then in your update statement do this:
update T
set T.property1 = dbo.myUdf(...)
from #temp_table_name T
where ... are any parameters it may need from the row to do its job.
I need to use a temporary variable declared in stored procedure. I need to use this variable to assign a value and do some function in a Matched statement. How can I use? is there any other way to have value??
Thanks in advance
This is how you can define a local variable in SQL Server:
DECLARE #MyVariable INT
SET #MyVariable = 12
SELECT HouseNumber + #MyVariable as NewHouseNumber FROM MyTable WHERE Id = 1
If you declare the variable preceding the MERGE statement then you can indeed use that variable within the MERGE statement. This apples to table variables as well as scalar variables.
I think he ment something like this
MERGE TargetTable as tar
USING SourceTable as src
ON tar.SomeID = src.OtherID
DECLARE #BossId INT
SET #BossId = (SELECT ID FROM EmployeeTable WHERE [BossID] = src.BossID)
--Here we take dynamicly an ID from another table
WHEN NOT MATCHED THEN
INSERT (list OF fields, [BossID])
VALUES (list OF values, #BossId)
WHEN MATCHED THEN
UPDATE
SET (list OF SET statements);
This way in every INSERT statement will have different BossID. Is this even possible? If not - How to insert records this way? Imagine that the SourceTable (which in my case is an input parameter in a SP) came with ID which needs to be mapped with another talbe. Any suggestions?
My post is more like an addition to the original question.