Get updated row as XML - sql-server

Is there any way to get the last updated row as XML in sql server?
Consider this snippet
DECLARE #table TABLE (
NAME NVARCHAR(255)
,Col2 INT
)
INSERT INTO #table
VALUES (
'a1'
,1
)
INSERT INTO #table
VALUES (
'a2'
,2
)
UPDATE #table
SET NAME = 'hello'
OUTPUT inserted.*
WHERE Col2 = 2
The above statements outputs the updated row. How can I output the row as XML, as I would do with a SELECT statement?
I tried the SELECT syntax, but was unsuccessful.
UPDATE #table
SET NAME = 'hello'
OUTPUT (inserted.* FOR XML AUTO)
WHERE Col2 = 2
Is there any way to accomplish this other than writing it to a table and selecting from the table?

Is there any way to accomplish this other than writing it to a table
and selecting from the table?
Not that I know of. Create a table variable where you insert the output from the update and then use that to create the XML output you want.
DECLARE #table TABLE
(
NAME NVARCHAR(255),
Col2 INT
);
INSERT INTO #table VALUES ('a1', 1);
INSERT INTO #table VALUES ('a2', 2);
DECLARE #updateresult TABLE
(
NAME NVARCHAR(255),
Col2 INT
);
UPDATE #table
SET NAME = 'hello'
OUTPUT inserted.NAME,
inserted.Col2
INTO #updateresult(Name, Col2)
WHERE Col2 = 2
SELECT NAME, Col2
FROM #updateresult
FOR XML PATH('row');

Related

Insert ... select output clause, get both INSERTED.ID and SELECTED.ID

I am a duplicating a mindmap in my database. The structure is mindmap->nodes->links. ("->" is one to many).
The below snippet is duplicating the nodes.
DECLARE #mindmapNodes table(Id int, OldId int);
INSERT INTO [dbo].[MindmapNodes]
(
[MindmapId],
[Loc],
[Title],
[SnippetId]
)
OUTPUT INSERTED.Id
INTO #mindmapNodes
SELECT #mindmapId as [MindmapId]
,[Loc]
,[Title]
,[SnippetId]
FROM [dbo].[MindmapNodes] mindmapNodes
I need mindmapNodes.[Id] as OldId in the output clause. This will allow me to change [MindmapLinks].[From] and [MindmapLinks].[To] from the original node to the new duplicated node.
Is there a way to do this?
Tables:
SELECT [Id]
,[Name]
,[DateCreated]
,[DateModified]
,[OwnerId]
FROM [dbo].[Mindmaps]
SELECT [Id]
,[MindmapId]
,[Loc]
,[Title]
,[SnippetId]
FROM [dbo].[MindmapNodes]
SELECT [Id]
,[From]
,[To]
,[FromPort]
,[ToPort]
,[MindmapId]
FROM [dbo].[MindmapLinks]
[MindmapLinks].[From]
[MindmapLinks].[To]
Are foreign keys to [MindmapNodes].[Id]
Found an answer here: https://social.msdn.microsoft.com/Forums/sqlserver/en-US/8cf1e38e-a29b-4ad7-abc7-b9fe2b987698/insert-into-using-select-with-output-into-multipart-identifier-could-not-be-bound?forum=transactsql
Tom:
You can't use columns from the SELECT part of an INSERT ... SELECT in
the OUTPUT clause. The only columns an INSERT statement can use in
the OUTPUT clause is columns in the inserted pseudo table.
Fortunately, there is a way around this restriction. Use MERGE to
simulate an INSERT by using an ON condition that is always false.
Here is the code:
select *
into #temp
from [dbo].[MindmapNodes]
where [MindmapId] = 215
DECLARE #mindmapNodes table(Id int, OldId int);
MERGE INTO [dbo].[MindmapNodes]
USING #temp AS cf
ON 1= 0
WHEN NOT MATCHED THEN
INSERT
( [MindmapId],
[Loc],
[Title],
[SnippetId]
)
Values
(
216,
cf.Loc,
cf.Title,
cf.SnippetId
)
Output inserted.[Id], cf.[Id] INTO #mindmapNodes;

SQL Server : Wrong Enconding on Select with Union

I got multiple tables, all of the same structure, containing the same columns. The columns are all varchar(250).
Now I have a query, that connects all the tables via UNION ALL and selects a column named InsertX that contains values like "134,856710602534"
My problem is: after UNIONing all the tables and selecting the InsertX column 134,856710602534 becomes 134ΒΈ856710602534. So the comma gets messed up. I tried different commands like CAST (InsertX AS varchar(250)) and Collate Latin1_General_CI_AS in the SELECT query, but nothing helps.
Are you sure it is the raw SQL that is converting that vs what is consuming it? I created the following text and it still has commas:
DECLARE #tbl1 TABLE (
COL1 VARCHAR(250)
);
DECLARE #tbl2 TABLE (
COL1 VARCHAR(250)
);
INSERT INTO #tbl1
( COL1 )
VALUES ( '134,856710602534' -- COL1 - varchar(250)
)
INSERT INTO #tbl2
( COL1 )
VALUES ( '134,856710602874' -- COL1 - varchar(250)
);
SELECT COL1
FROM #tbl1
UNION ALL
SELECT COL1
FROM #tbl2
The problem was the third-party-application...
Thank you for your help anyway!

mssql multiple queries insert queries and results

In php I'm executing multiple queries at once, the queries are wrote in one big variable.
These are insert queries and I have to retrieve each autoincrement "id" of the records created in the db. How to do it ?
The results set retrieved don't seems to keep each single result but just one.
I think that you are talking about an OUTPUT clause from the insert statement.
http://msdn.microsoft.com/en-us/library/ms177564.aspx
CREATE TABLE #t (id int identity (1, 1), f1 nvarchar(20 ) ) --the table that has the identities
CREATE TABLE #ids ( id int ) --the table to store the inserts into table #t
INSERT INTO #t ( f1 ) OUTPUT INSERTED.id INTO #ids SELECT N'AAAA'
INSERT INTO #t ( f1 ) OUTPUT INSERTED.id INTO #ids SELECT N'BBBB'
INSERT INTO #t ( f1 ) OUTPUT INSERTED.id INTO #ids SELECT N'CCCC'
SELECT * FROM #t
SELECT * FROM #ids
Another way is to use ##IDENTITY or SCOPE_IDENTITY() SQL Authority link discussing/comparing them
CREATE TABLE #t (id int identity (1, 1), f1 nvarchar(20 ) )
CREATE TABLE #ids ( id int )
INSERT INTO #t ( f1 ) SELECT N'AAAA'
INSERT INTO #ids SELECT ##IDENTITY --OR you can use SELECT SCOPE_IDENTITY()
INSERT INTO #t ( f1 ) SELECT N'BBBB'
INSERT INTO #ids SELECT ##IDENTITY --OR you can use SELECT SCOPE_IDENTITY()
INSERT INTO #t ( f1 ) SELECT N'CCCC'
INSERT INTO #ids SELECT ##IDENTITY --OR you can use SELECT SCOPE_IDENTITY()
SELECT * FROM #t
SELECT * FROM #ids

tsql return identity values when inserting multiple records into a view

I have a situation where I need to insert multiple records/batch insert into a view which has instead of trigger. How can I retrieve the inserted identity values? I tried using the OUTPUT clause to retrieve the Id from the Inserted table but it always returns null.
Using this setup.
create table InsteadOf
(
ID int identity primary key,
Name varchar(10) not null
)
go
create view v_InsteadOf
as
select ID, Name
from InsteadOf
go
create trigger tr_InsteadOf on InsteadOf instead of insert
as
begin
insert into InsteadOf(Name)
select Name
from inserted
end
The statement
insert into v_InsteadOf(Name)
output inserted.*
select 'Name1' union all
select 'Name2'
Will give you an error.
Msg 334, Level 16, State 1, Line 4 The target table 'InsteadOf' of the
DML statement cannot have any enabled triggers if the statement
contains an OUTPUT clause without INTO clause.
Using an INTO clause with the insert instead.
declare #IDs table(ID int, Name varchar(10))
insert into v_InsteadOf(Name)
output inserted.* into #IDs
select 'Name1' union all
select 'Name2'
select *
from #IDs
Gives you 0 as a value not null.
ID Name
----------- ----------
0 Name1
0 Name2
You can put the output clause in the trigger.
create trigger tr_InsteadOf on InsteadOf instead of insert
as
begin
insert into InsteadOf(Name)
output inserted.*
select Name
from inserted
end
And the output will be generated for you when you do the insert.
insert into v_InsteadOf(Name)
select 'Name1' union all
select 'Name2'
Result:
ID Name
----------- ----------
1 Name1
2 Name2
Update:
To capture the output from the insert statement you can use insert into ... exec (...)
declare #T table
(
ID int,
Name varchar(10)
)
insert into #T
exec
(
'insert into v_InsteadOf(Name)
values (''Name1''),(''Name2'')'
)

Inserting batch of rows into two tables in SQL Server 2008

I have a requirement to insert multiple rows into table1 and at the same time insert a row into table2 with a pkID from table1 and a value that comes from a SP parameter.
I created a stored procedure that performs a batch insert with a table valued parameter which contains the rows to be inserted into table1. But I have a problem with inserting the row into table2 with the corresponding Id (identity) from table1, along with parameter value that I have passed.
Is there anyone who implemented this, or what is the good solution for this?
CREATE PROCEDURE [dbo].[oSP_TV_Insert]
#uID int
,#IsActive int
,#Type int -- i need to insert this in table 2
,#dTableGroup table1 READONLY -- this one is a table valued
AS
DECLARE #SQL varchar(2000)
DECLARE #table1Id int
BEGIN
INSERT INTO dbo.table1
(uID
,Name
,Contact
,Address
,City
,State
,Zip
,Phone
,Active)
SELECT
#uID
,Name
,Contact
,Address
,City
,State
,Zip
,Phone
,Active
,#G_Active
FROM #dTableGroup
--the above query will perform batch insert using the records from dTableGroup which is table valued
SET #table1ID = SCOPE_IDENTITY()
-- this below will perform inserting records to table2 with every Id inserted in table1.
Insert into table2(#table1ID , #type)
You need to temporarily store the inserted identity values and then create a second INSERT statement - using the OUTPUT clause.
Something like:
-- declare table variable to hold the ID's that are being inserted
DECLARE #InsertedIDs TABLE (ID INT)
-- insert values into table1 - output the inserted ID's into #InsertedIDs
INSERT INTO dbo.table1(ID, Name, Contact, Address, City, State, Zip, Phone, Active)
OUTPUT INSERTED.ID INTO #InsertedIDs
SELECT
#ID, Name, Contact, Address, City, State, Zip, Phone, Active, #G_Active
FROM #dTableGroup
and then you can have your second INSERT statement:
INSERT INTO dbo.table2(Table1ID, Type)
SELECT ID, #type FROM #InsertedIDs
See the MSDN docs on the OUTPUT clause for more details on what you can do with the OUTPUT clause - one of the most underused and most "unknown" features of SQL Server these days!
Another approach using OUTPUT clause and only one statement for inserting data in both destination tables:
--Parameters
DECLARE #TableGroup TABLE
(
Name NVARCHAR(100) NOT NULL
,Phone VARCHAR(10) NOT NULL
);
DECLARE #Type INT;
--End Of parameters
--Destination tables
DECLARE #FirstDestinationTable TABLE
(
FirstDestinationTableID INT IDENTITY(1,1) PRIMARY KEY
,Name NVARCHAR(100) NOT NULL
,Phone VARCHAR(10) NOT NULL
);
DECLARE #SecondDestinationTable TABLE
(
SecondDestinationTable INT IDENTITY(2,2) PRIMARY KEY
,FirstDestinationTableID INT NOT NULL
,[Type] INT NOT NULL
,CHECK([Type] > 0)
);
--End of destination tables
--Test1
--initialization
INSERT #TableGroup
VALUES ('Bogdan SAHLEAN', '0721200300')
,('Ion Ionescu', '0211002003')
,('Vasile Vasilescu', '0745600800');
SET #Type = 9;
--execution
INSERT #SecondDestinationTable (FirstDestinationTableID, [Type])
SELECT FirstINS.FirstDestinationTableID, #Type
FROM
(
INSERT #FirstDestinationTable (Name, Phone)
OUTPUT inserted.FirstDestinationTableID
SELECT tg.Name, tg.Phone
FROM #TableGroup tg
) FirstINS
--check records
SELECT *
FROM #FirstDestinationTable;
SELECT *
FROM #SecondDestinationTable;
--End of test1
--Test2
--initialization
DELETE #TableGroup;
DELETE #FirstDestinationTable;
DELETE #SecondDestinationTable;
INSERT #TableGroup
VALUES ('Ion Ionescu', '0210000000')
,('Vasile Vasilescu', '0745000000');
SET #Type = 0; --Wrong value
--execution
INSERT #SecondDestinationTable (FirstDestinationTableID, [Type])
SELECT FirstINS.FirstDestinationTableID, #Type
FROM
(
INSERT #FirstDestinationTable (Name, Phone)
OUTPUT inserted.FirstDestinationTableID
SELECT tg.Name, tg.Phone
FROM #TableGroup tg
) FirstINS
--check records
DECLARE #rc1 INT, #rc2 INT;
SELECT *
FROM #FirstDestinationTable;
SET #rc1 = ##ROWCOUNT;
SELECT *
FROM #SecondDestinationTable;
SET #rc2 = ##ROWCOUNT;
RAISERROR('[Test2 results] #FirstDestinationTable: %d rows; ##SecondDestinationTable: %d rows;',1,1,#rc1,#rc2);
--End of test1
Since you need all inserted identity values, look at the output clause of the insert statement: http://msdn.microsoft.com/en-us/library/ms177564.aspx

Resources