The xml type
SQL server supports an XML datatype; we use singlle-quotes to denote its values, but it is not quite a varchar type. Below we define a table Person, with id, name and an XML field called SkillsXML; we insert two rows. The xml looks like <skills> <skill level="High"> SQL</skill> ... </skills>.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CREATE TABLE People ( | |
id int primary key, | |
name varchar(20), | |
SkillsXml xml | |
); | |
INSERT INTO People(id,name,SkillsXml) VALUES(1,'Orlando', | |
'<skills> | |
<skill level="High">SQL</skill> | |
<skill level="Medium">C#</skill> | |
</skills>'); | |
INSERT INTO People(id,name,SkillsXml) VALUES(2,'Lina', | |
'<skills> | |
<skill level="Low">SQL</skill> | |
<skill level="Medium">Java</skill> | |
</skills>'); | |
Simple queries
With this, we can use the query method of the xml datatype to select only certain nodes; for example, the following query would select only the first skill for each person. Notice we're using an XPath expression for selecting here; simple XPath expressions look like folders; here we're selecting from the root of the document, the skills node, and from there the first skill node (notice XPath starts counting at 1, not 0).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SELECT id,name, SkillsXml.query('/skills/skill[1]') | |
FROM People |
Getting the value of an attribute
We can also use the value method, which allows us to get the value of an XML attribute; this method takes 2 arguments, an XPath expression and a string with a SQL datatype; the value of the XPath expression will be cast (or converted) to that type. The following query gets the value of the level attribute of the first skill.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SELECT id,name, SkillsXml.value('(/skills/skill[1]/@level)[1]','varchar(10)') | |
FROM People |
Nodes queries
The most interesting queries use the nodes xml operator; with this, and cross apply (or outer apply) we can get one row per xml element; for example, the following query gets us each person with their skills; since each of our person rows has 2 skills, we will get 4 rows total.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
SELECT P.*, Skill.query('.') | |
FROM People P CROSS APPLY SkillsXml.nodes('/skills/skill') as Skills(Skill) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
WITH | |
PeopleAndSkills AS ( | |
SELECT P.*, | |
cast(Skill.query('./text()') as varchar) as SkillName, | |
Skill.value('(./@level)[1]' ,'varchar(20)') as SkillLevel | |
FROM People P CROSS APPLY SkillsXml.nodes('/skills/skill') as Skills(Skill) | |
) | |
SELECT * from PeopleAndSkills | |
WHERE SkillLevel='Medium' |