There are five or more database tables, that are related to each other like in the following database schema:
Here is the code for creating them:
-- Table 1
CREATE TABLE [dbo].[Table1](
[Id] [INT] NOT NULL,
[Title] [NCHAR](10) NOT NULL,
[Annotation] [NCHAR](10) NOT NULL,
CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
-- Table 2 referencing Table 1
CREATE TABLE [dbo].[Table2](
[Id] [INT] NOT NULL,
[Table1_Id] [INT] NOT NULL,
[Title] [NCHAR](10) NOT NULL,
CONSTRAINT [PK_Table2] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Table2] WITH CHECK ADD CONSTRAINT [FK_Table2_Table1] FOREIGN KEY([Table1_Id])
REFERENCES [dbo].[Table1] ([Id])
GO
ALTER TABLE [dbo].[Table2] CHECK CONSTRAINT [FK_Table2_Table1]
GO
-- Table 2_1 referencing Table 2
CREATE TABLE [dbo].[Table2_1](
[Id] [INT] NOT NULL,
[Table2_Id] [INT] NOT NULL,
[Title] [NCHAR](10) NOT NULL,
CONSTRAINT [PK_Table2_1] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Table2_1] WITH CHECK ADD CONSTRAINT [FK_Table2_1_Table2] FOREIGN KEY([Table2_Id])
REFERENCES [dbo].[Table2] ([Id])
GO
ALTER TABLE [dbo].[Table2_1] CHECK CONSTRAINT [FK_Table2_1_Table2]
GO
-- Table 3 referencing Table 1
CREATE TABLE [dbo].[Table3](
[Id] [INT] NOT NULL,
[Table1_Id] [INT] NOT NULL,
[Title] [NCHAR](10) NOT NULL,
CONSTRAINT [PK_Table3] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Table3] WITH CHECK ADD CONSTRAINT [FK_Table3_Table1] FOREIGN KEY([Table1_Id])
REFERENCES [dbo].[Table1] ([Id])
GO
ALTER TABLE [dbo].[Table3] CHECK CONSTRAINT [FK_Table3_Table1]
GO
-- Table 3_1 referencing Table 3
CREATE TABLE [dbo].[Table3_1](
[Id] [INT] NOT NULL,
[Table3_Id] [INT] NOT NULL,
[Title] [NCHAR](10) NOT NULL,
CONSTRAINT [PK_Table3_1] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Table3_1] WITH CHECK ADD CONSTRAINT [FK_Table3_1_Table3] FOREIGN KEY([Table3_Id])
REFERENCES [dbo].[Table3] ([Id])
GO
ALTER TABLE [dbo].[Table3_1] CHECK CONSTRAINT [FK_Table3_1_Table3]
GO
Now I add the following record samples to the table:
INSERT INTO table1 VALUES (1, 'FirstTitle', 'FirstAnno')
INSERT INTO table2 VALUES (1, 1, 'Tab2Title')
INSERT INTO table3 VALUES (1, 1, 'Tab3Title')
INSERT INTO table2_1 VALUES (1, 1, 'Tab21Sub')
INSERT INTO table3_1 VALUES (1, 1, 'Tab31Sub')
Querying this tables with a JOIN FOR XML like
SELECT * FROM Table1 AS T1
JOIN Table2 AS T2 ON T1.Id = T2.Table1_Id
JOIN Table3 AS T3 ON T1.Id = T3.Table1_Id
JOIN Table2_1 AS T21 ON T2.Id = T21.Table2_Id
JOIN Table3_1 AS T31 ON T3.Id = T31.Table2_Id
FOR XML AUTO
will end in this result
<T1 Id="1" Title="FirstTitle" Annotation="FirstAnno ">
<T2 Id="1" Table1_Id="1" Title="Tab2Title ">
<T3 Id="1" Table1_Id="1" Title="Tab3Title ">
<T21 Id="1" Table2_Id="1" Title="Tab21Sub ">
<T31 Id="1" Table3_Id="1" Title="Tab31Sub " />
</T21>
</T3>
</T2>
</T1>
while I'm expecting this
<T1 Id="1" Title="FirstTitle" Annotation="FirstAnno ">
<T2 Id="1" Table1_Id="1" Title="Tab2Title ">
<T21 Id="1" Table2_Id="1" Title="Tab21Sub" />
</T2>
<T3 Id="1" Table1_Id="1" Title="Tab3Title ">
<T31 Id="1" Table3_Id="1" Title="Tab31Sub" />
</T3>
</T1>
So how can I modify the query, perhaps making subqueries to get the expected result, sorting Table 3 at the same level and not beneath table2, and also sorting the childs of table2_1 and table3_1 beneath there parents?
Given your hierarchical example I've fleshed out the example data to include some more subitems...
INSERT INTO table1 VALUES (1, 'FirstTitle', 'FirstAnno');
INSERT INTO table2 VALUES (1, 1, 'Tab2Title1');
INSERT INTO table2_1 VALUES (1, 1, 'Tab21Sub1.1');
INSERT INTO table2_1 VALUES (2, 1, 'Tab21Sub1.2');
INSERT INTO table2_1 VALUES (3, 1, 'Tab21Sub1.3');
INSERT INTO table2 VALUES (2, 1, 'Tab2Title2');
INSERT INTO table2_1 VALUES (4, 2, 'Tab21Sub2.1');
INSERT INTO table2_1 VALUES (5, 2, 'Tab21Sub2.2');
INSERT INTO table3 VALUES (1, 1, 'Tab3Title1');
INSERT INTO table3_1 VALUES (1, 1, 'Tab31Sub');
INSERT INTO table3 VALUES (2, 1, 'Tab3Title2');
If you use FOR XML AUTO
and correlated subqueries that return FOR XML AUTO, TYPE
such as the following:
SELECT T1.*,
(
SELECT T2.*,
(
SELECT T21.*
FROM Table2_1 AS T21
WHERE T2.Id = T21.Table2_Id
FOR XML AUTO, TYPE
)
FROM Table2 AS T2
WHERE T1.Id = T2.Table1_Id
FOR XML AUTO, TYPE
),
(
SELECT T3.*,
(
SELECT T31.*
FROM Table3_1 AS T31
WHERE T3.Id = T31.Table3_Id
FOR XML AUTO, TYPE
)
FROM Table3 AS T3
WHERE T1.Id = T3.Table1_Id
FOR XML AUTO, TYPE
)
FROM Table1 AS T1
FOR XML AUTO;
You can return nested XML data such as the following:
<T1 Id="1" Title="FirstTitle" Annotation="FirstAnno ">
<T2 Id="1" Table1_Id="1" Title="Tab2Title1">
<T21 Id="1" Table2_Id="1" Title="Tab21Sub1.1"/>
<T21 Id="2" Table2_Id="1" Title="Tab21Sub1.2"/>
<T21 Id="3" Table2_Id="1" Title="Tab21Sub1.3"/>
</T2>
<T2 Id="2" Table1_Id="1" Title="Tab2Title2">
<T21 Id="4" Table2_Id="2" Title="Tab21Sub2.1"/>
<T21 Id="5" Table2_Id="2" Title="Tab21Sub2.2"/>
</T2>
<T3 Id="1" Table1_Id="1" Title="Tab3Title1">
<T31 Id="1" Table3_Id="1" Title="Tab31Sub "/>
</T3>
<T3 Id="2" Table1_Id="1" Title="Tab3Title2"/>
</T1>