Reputation: 97
I need to return a particular column as an element in the xml returned with the FOR XML AUTO clause in the sql server. Automatic return turns all fields into attributes of the corresponding element. Okay, but one field or another I need it to be an element.
I have two tables:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table1](
[Id] [int] NULL,
[Nome] [varchar](50) NULL
) ON [PRIMARY]
GO
/****** Object: Table [dbo].[Table2] Script Date: 02/03/2018 16:24:11 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Table2](
[Id] [int] NULL,
[DataVencimento] [date] NULL,
[Table1_Id] [int] NULL
) ON [PRIMARY]
GO
INSERT [dbo].[Table1] ([Id], [Nome]) VALUES (1, N'AAA')
GO
INSERT [dbo].[Table1] ([Id], [Nome]) VALUES (2, N'BBB')
GO
INSERT [dbo].[Table1] ([Id], [Nome]) VALUES (3, N'CCC')
GO
INSERT [dbo].[Table2] ([Id], [DataVencimento], [Table1_Id]) VALUES (1, CAST(N'2018-01-01' AS Date), 1)
GO
INSERT [dbo].[Table2] ([Id], [DataVencimento], [Table1_Id]) VALUES (2, CAST(N'2018-01-02' AS Date), 2)
GO
INSERT [dbo].[Table2] ([Id], [DataVencimento], [Table1_Id]) VALUES (3, CAST(N'2018-01-03' AS Date), 2)
GO
I have the following relationship between them:
select
Table1.Id,
Table1.Nome,
Table2.Id,
Table2.DataVencimento
from Table1
inner join Table2 on Table2.Table1_Id = Table1.Id
order by Table1.Id, Table2.Id
for xml auto, root('ArrayOfTable1')
which returns:
<ArrayOfTable1>
<Table1 Id="1" Nome="AAA">
<Table2 Id="1" DataVencimento="2018-01-01" />
</Table1>
<Table1 Id="2" Nome="BBB">
<Table2 Id="2" DataVencimento="2018-01-02" />
<Table2 Id="3" DataVencimento="2018-01-03" />
</Table1>
</ArrayOfTable1>
But I need DataVencimento to be an element, like this:
<ArrayOfTable1>
<Table1 Id="1" Nome="AAA">
<Table2 Id="1">
<DataVencimento>2018-01-01</DataVencimento>
</Table2>
</Table1>
<Table1 Id="2" Nome="BBB">
<Table2 Id="2">
<DataVencimento>2018-01-02</DataVencimento>
</Table2>
<Table2 Id="3">
<DataVencimento>2018-01-03</DataVencimento>
</Table2>
</Table1>
</ArrayOfTable1>
How to do this?
Upvotes: 2
Views: 507
Reputation: 67311
In most cases FOR XML PATH()
is the prefered approach. With PATH
you have full control over the output. Nothing is automatic...
Try it out:
SELECT t1.Id AS [@id]
,t1.Nome AS [@Nome]
,(
SELECT t2.Id AS [@Id]
,t2.DataVencimento
FROM dbo.Table2 AS t2
WHERE t1.Id=t2.Table1_Id
ORDER BY t2.Id
FOR XML PATH('Table2'),TYPE
)
FROM dbo.Table1 AS t1
WHERE EXISTS(SELECT 1 FROM dbo.Table2 WHERE Table2.Table1_Id=t1.Id)
ORDER BY t1.Id
FOR XML PATH('Table1'), ROOT('ArrayOfTable1');
Upvotes: 0
Reputation: 9299
select
Table1.ID,
Table1.Nome,
Table2.Id,
(select table2.DataVencimento for xml path(''), elements, type)
from Table1
inner join Table2 on Table2.Table1_Id = Table1.Id
order by Table1.Id, Table2.Id
for xml auto, root('ArrayOfTable1')
output:
<ArrayOfTable1>
<Table1 ID="1" Nome="AAA">
<Table2 Id="1">
<DataVencimento>2018-01-01</DataVencimento>
</Table2>
</Table1>
<Table1 ID="2" Nome="BBB">
<Table2 Id="2">
<DataVencimento>2018-01-02</DataVencimento>
</Table2>
<Table2 Id="3">
<DataVencimento>2018-01-03</DataVencimento>
</Table2>
</Table1>
</ArrayOfTable1>
http://sqlfiddle.com/#!18/71fe9/29
Upvotes: 1
Reputation: 19
I don't now if there is a cleaner solution but something like this should work:
select
Table1.Id as [@Id],
Table1.Nome as [@Nome],
[inner].[xml] as [*]
from Table1
outer apply
( select (select
Table2.Id as [@Id],
Table2.DataVencimento
from Table2
where Table2.Table1_Id = Table1.Id
for xml path('Table2'), type) as [xml]
) as [inner]
inner join Table2 on Table2.Table1_Id = Table1.Id
order by Table1.Id, Table2.Id
for xml path('Table1'), root('ArrayOfTable1')
Upvotes: 1