FOR XML EXPLICIT – Part 1

Posted on December 5th, 2007

<Agents>

With SQL Server 2005 we can generate XML output using different methods. Using TSQL keyword FOR XML along with AUTO, RAW, PATH and EXPLICIT we could generate almost any XML structure that we might need. PATH is a very powerful keyword which allows a great deal of customization on the structure of the generated XML and is relatively easy to use. EXPLICIT provides more control over the generated XML structure but it is much more complex then other methods. Most of the times, we could generate the same output as EXPLICIT by using PATH. But some times, the structure of the XML output might be too complex for PATH to generate, and we will have to go with EXPLICIT.

PATH is available only in SQL Server 2005. If you are working with SQL server 2000, you will have to work with EXPLICIT if you need control over the XML structure being generated. I had been helping some people on writing TSQL queries with EXPLICIT recently, at some of the Internet forums. My observation is that most of the times people get an error because of the sort order of the result set being passed to FOR XML EXPLICIT

I worked with Vimal Rughani recently on such a query. After we wrote the query, he asked me if I could explain the flow of the code. I thought that it would be a good idea to write down the steps I went through while writing the query, so that it will help other people around too. He wanted to generate the following XML output using FOR XML EXPLICIT.

<Agent AgentID=”1″>

<Fname>Vimal</Fname>

<SSN>123-23-4521</SSN>

<AddressCollection>

<Address>

<AddressType>Home</AddressType>

<Address1>abc</Address1>

<Address2>xyz road</Address2>

<City>RJ</City>

</Address>

<Address>

<AddressType>Office</AddressType>

<Address1>temp</Address1>

<Address2>ppp road</Address2>

<City>RJ</City>

</Address>

</AddressCollection>

</Agent>

<Agent AgentID=”2″>

<Fname>Jacob</Fname>

<SSN>321-52-4562</SSN>

<AddressCollection>

<Address>

<AddressType>Home</AddressType>

<Address1>xxx</Address1>

<Address2>aaa road</Address2>

<City>NY</City>

</Address>

<Address>

<AddressType>Office</AddressType>

<Address1>ccc</Address1>

<Address2>oli Com</Address2>

<City>CL</City>

</Address>

<Address>

<AddressType>Temp</AddressType>

<Address1>eee</Address1>

<Address2>olkiu road</Address2>

<City>CL</City>

</Address>

</AddressCollection>

</Agent>

<Agent AgentID=”3″>

<Fname>Tom</Fname>

<SSN>252-52-4563</SSN>

<AddressCollection>

<Address>

<AddressType>Home</AddressType>

<Address1>ttt</Address1>

<Address2>loik road</Address2>

<City>NY</City>

</Address>

</AddressCollection>

</Agent>

</Agents>

The data should come from two tables Agents and Addresses. Before we write the query, we need to create those tables and populate them with some data. For the purpose of this example, we may not need any physical tables. We could go with memory tables. The following code will create two memory tables and fill them with data. The code is written by Kent in one of the MSDN forums.

/*

Borrowed from Kent’s code

*/

declare @agent table

(

AgentID int,

Fname varchar(5),

SSN varchar(11)

)

insert into @agent

select 1, ‘Vimal’, ’123-23-4521′ union all

select 2, ‘Jacob’, ’321-52-4562′ union all

select 3, ‘Tom’, ’252-52-4563′

declare @address table

(

AddressID int,

AddressType varchar(12),

Address1 varchar(20),

Address2 varchar(20),

City varchar(25),

AgentID int

)

insert into @address

select 1, ‘Home’, ‘abc’, ‘xyz road’, ‘RJ’, 1 union all

select 2, ‘Office’, ‘temp’, ‘ppp road’, ‘RJ’, 1 union all

select 3, ‘Home’, ‘xxx’, ‘aaa road’, ‘NY’, 2 union all

select 4, ‘Office’, ‘ccc’, ‘oli Com’, ‘CL’, 2 union all

select 5, ‘Temp’, ‘eee’, ‘olkiu road’, ‘CL’, 2 union all

select 6, ‘Home’, ‘ttt’, ‘loik road’, ‘NY’, 3

Let us start writing the query. Because we write this query for learning purpose,
I would like to take an approach by which we will progressively develop the complete
query.

So let us start with the root node. Let us first create the query for generating the root node.

SELECT

1 AS Tag,

NULL AS Parent,

NULL AS ‘Agents!1!’

FOR XML EXPLICIT

This will generate the root node that we need.

<Agents />

Now let us write the code for generating next level. The next level is the agent node. This information should come from the agent table. Let us  add the code for that.

SELECT

1 AS Tag,

NULL AS Parent,

NULL AS ‘Agents!1!’,

NULL AS ‘Agent!2!AgentID’

UNION ALL

SELECT

2 AS Tag,

1 AS Parent,

NULL,

AgentID

FROM @agent

FOR XML EXPLICIT

Note the code in yellow. This is what we added to the previous version. This query generates the following output.

<Agents>

<Agent AgentID=”1″ />

<Agent AgentID=”2″ />

<Agent AgentID=”3″ />

</Agents>

Good so far. Let us add fname and ssn under the agent node as child elements.

SELECT

1 AS Tag,

NULL AS Parent,

NULL AS ‘Agents!1!’,

NULL AS ‘Agent!2!AgentID’,

NULL AS ‘Agent!2!Fname!Element’,

NULL AS ‘Agent!2!SSN!Element’

UNION ALL

SELECT

2 AS Tag,

1 AS Parent,

NULL,

AgentID,

Fname,

SSN

FROM @agent

FOR XML EXPLICIT

This version will give us the following output.

<Agents>

<Agent AgentID=”1″>

<Fname>Vimal</Fname>

<SSN>123-23-4521</SSN>

</Agent>

<Agent AgentID=”2″>

<Fname>Jacob</Fname>

<SSN>321-52-4562</SSN>

</Agent>

<Agent AgentID=”3″>

<Fname>Tom</Fname>

<SSN>252-52-4563</SSN>

</Agent>

</Agents>

Due to some unknown reasons, Windows Live Writer does not allow me to write further in this post. Hence I am putting the rest of the code to another post.

XML Workshop

Posted on December 5th, 2007
  1. XML Workshop I – Generating XML with FOR XML
  2. XML Workshop II – Reading values from XML variables
  3. XML Workshop III – FOR XML PATH
  4. XML Workshop IV – FOR XML EXPLICIT
  5. XML Workshop V – Reading Values from XML Columns
  6. XML Workshop VI – Typed XML and SCHEMA Collection
  7. XML Workshop VII – Validating values with SCHEMA
  8. XML Workshop VIII – Custom Types and Inheritance
  9. XML Workshop IX – Mixed Types
  10. XML Workshop X – Working with namespaces
  11. XML Workshop XI – Default Namespaces
  12. XML Workshop XII – Parsing a delimited string
  13. XML Workshop XIII – XSD And Variable Content Containers
  14. XML Workshop XIV – Generating an XML Tree
  15. XML Workshop XV – Accessing FOR XML results with ADO.NET
  16. XML Workshop XVI – Shaping the XML results
  17. XML Workshop XVII – Writing a LOOP to process all XML nodes
  18. XML Workshop XVIII – Generating an RSS 2.0 Feed with TSQL

SQLCE Workshop III – Getting started with 3.5 Beta

Posted on December 5th, 2007

Provides a basic introduction to SQL CE 3.5 beta which involves installation, creating a database and tables, connecting to the database file and inserting records to the newly created table from VB.NET as well as C#.NET.

Read the article

SQL Server 2005 Replication – Adding two articles with same name in different schemas

Posted on December 5th, 2007

I came across a very strange problem recently while creating a publication. I had objects with the same name but in different schemas. For example, “dbo.Invoices”, “Billing.Invoices”, “AR.Invoices” and “AP.Invoices”. In my case, the first object was a TABLE and the other 3 were VIEWS which selects data from the invoice table. I added “dbo.Invoices” to the publication and then tried to add the other 3 views. That is where the trouble started.

When I tried to add “Billing.Invoices”, I got an error which said “Article ‘Invoices’ already exists in the publication”. It looked like the UI (Property Page of Publication) does not consider the schema of the object being added.

I got the problem resolved by adding the article using TSQL instead of the UI page. I used the following code to add the new article to the publication.

exec sp_addarticle

@publication = N’MyPublicationName’,

@article = N’Billing_Invoices’,

–I gave a different name to the article

@source_owner = N’Billing’,

@source_object = N’Invoics’,

@type = N’view schema only’,

@description = N”,

@creation_script = N”,

@pre_creation_cmd = N’drop’,

@schema_option = 0×0000000008000001,

@destination_table = N’Invoices’,

@destination_owner = N’Billing’,

@status = 16

XML Workshop V – Reading Values from XML Columns

Posted on November 5th, 2007

If you are new to XQuery, you might find it little tricky to read values from an XML column. Reading a value from an XML variable is slightly different from reading values from an XML column. In an XML variable we have a single XML document. But the case of an XML column is different. When you query a table, each row in the table has an XML document stored in it.

Let us look at an example. In the following example, we assign a value to an XML variable and Query it.

1 /*

2 Let us declare an XML variable and store a value.

3 */

4 DECLARE @x XML

5 SET @x =

6 ’<Name>

7     <First>Jacob</First>

8     <Last>Sebastian</Last>

9 </Name>’

10

11 /*

12 Query the XML variable.

13 */

14 SELECT

15     n.l.value(‘First[1]‘,’VARCHAR(20)’) AS First,

16     n.l.value(‘Last[1]‘,’VARCHAR(20)’) AS Last

17 FROM @x.nodes(‘/Name’) n(l)

18

19 /*

20 OUTPUT

21

22 First                Last

23 ——————– ——————–

24 Jacob                Sebastian

25

26 (1 row(s) affected)

27 */

That was pretty much simple. You will need a slightly modified version of this query, if you need to read the values from an XML column. We need to use CROSS APPLY so that we can access more than one record unlike the previous example, where we had only one variable.

1 /*

2 Let us create a table and insert an XML value.

3 */

4 CREATE TABLE Employees ( Emp XML )

5 INSERT INTO Employees ( Emp )

6 SELECT

7 ’<Name>

8     <First>Jacob</First>

9     <Last>Sebastian</Last>

10 </Name>’

11

12 /*

13 Let us try to query the table now

14 */

15 SELECT

16     n.l.value(‘First[1]‘,’VARCHAR(20)’) AS First,

17     n.l.value(‘Last[1]‘,’VARCHAR(20)’) AS Last

18 FROM Employees

19 CROSS APPLY Emp.nodes(‘//Name’) n(l)

20

21 /*

22 OUTPUT:

23

24 First                Last

25 ——————– ——————–

26 Jacob                Sebastian

27

28 (1 row(s) affected)

29 */

My XML Workshop V at SQLServerCentral presents a detailed tutorial which explains the usage of CROSS APPLY. It also presents a few different ways to query a table and retrieve different pieces of information.