0

I have an XML document saved in a Column as varchar(max). The text I want is surrounded by <Text> Words I Want</Text>but these Text tags repeat sometimes 4 or 5 times.

How do I loop through the same document x number of times dependent on the number of text tags?

Currently I'm using this to pull out the first bit of text

 DECLARE @first_char nvarchar(10)
DECLARE @second_char nvarchar(10)

SET @first_char = 'xt>';
SET @second_char = '</text>';

SELECT[TestId]
      ,[SectionId],
SUBSTRING
(
-- column
 settings
-- start position
,CHARINDEX(@first_char, Settings , 1) + 3
-- length
,CASE
WHEN (CHARINDEX(@second_char, Settings , 0) - CHARINDEX(@first_char, Settings, 0)) > 0
THEN CHARINDEX(@second_char, Settings, 0) - CHARINDEX(@first_char, Settings, 0) - 3
ELSE 0
END
) AS Response
FROM [B2IK-TestBuilder].[dbo].[Questions] 
group by [TestId]
      ,[SectionId], settings

and I know how many times the Text tag appears.

This is an example of the xml document saved a varchar(max):

<Settings>
  <ShowNotes>true</ShowNotes>
  <ShowComment>false</ShowComment>
  <TextBefore>From the six safety essentials, a </TextBefore>
  <TextAfter>is essential before any work is carried out?</TextAfter>
  <Items>
    <Item>
      <Text>Answer 1</Text>
    </Item>
    <Item>
      <Text>Answer 2</Text>
    </Item>
    <Item>
      <Text>Answer 3</Text>
    </Item>
    <Item>
      <Text>Answer 4</Text>
    </Item>
    <Item>
      <Text>Answer 5</Text>
    </Item>
    <Item>
      <Text>Answer 6</Text>
    </Item>

Thank you in advance.

1 Answers1

1

OK since SQL 2005 you can use XPath to query the data. I would recommend using the XML column type for the Settings column. Then you can use CROSS APPLY to get the Item nodes.

SELECT q.TestId,q.SectionId,x.XmlCol.value('(Text)[1]','VARCHAR(MAX)') 
    FROM Questions q
CROSS APPLY q.settings.nodes('/Settings/Items/Item') x(XmlCol);

If you for some reason cannot change the type of you settings column you could cast it in your statement.

SELECT q.TestId,q.SectionId,x.XmlCol.value('(Text)[1]','VARCHAR(MAX)') 
    FROM (SELECT TestId,SectionId, cast([settings] as xml) as Data FROM Questions) q
CROSS APPLY q.settings.nodes('/Settings/Items/Item') x(XmlCol);
codeworx
  • 2,715
  • 13
  • 12
  • That is BRILLIANT, is there a way of adding the order in which they appear in the XML? For example 1 Answer1, 2 Answer 2, 3 Answer 3? – user3774310 Jun 25 '14 at 09:26
  • Sure you can use it like any other column in your Statement. ORDER BY x.XmlCol.value('(Text)[1]','VARCHAR(MAX)') – codeworx Jun 25 '14 at 10:08
  • Oh sorry i got that question wrong. that is how you whould get the node position: x.XmlCol.value('for $i in . return count(../*[. << $i]) + 1', 'int') – codeworx Jun 25 '14 at 11:27