March 25, 2008 at 9:50 pm
Comments posted to this topic are about the item XML Workshop XVII - Writing a LOOP to process XML elements in TSQL
.
March 26, 2008 at 12:11 am
Cool One.!!
Another way to fetch the XML Element without loop will be by using the XQuery function Text.
For same xml this will work.
SELECT T.c.value('(Name/text())[1]', 'varchar(256)') as Name,T.c.value('(Department/text())[1]', 'varchar(256)') as Department
FROM @x.nodes('/Employees/Employee') T(c)
March 26, 2008 at 6:00 am
Another way using xquery if you have multiple Name elements as noted in this blog entry
http://blogs.msdn.com/mrorke/archive/2005/07/21/441554.aspx
SELECT T.ref.value('.', 'varchar(256)') AS Employee
FROM
(
select [Xml]=@x.query('
for $i in data(/Employees/Employee/Name) return
element temp { $i }
')
) A
cross apply A.Xml.nodes('/temp') T(ref)
March 26, 2008 at 6:36 am
Does anyone know whether the XML or T-SQL count() functions are equivalent in execution, or is one more efficient than the other.
Is there any significant difference between...
SELECT
@max-2 = @x.query('
{ count(/Employees/Employee) }
').value('e[1]','int')
and
select @max-2 = count(*) from
@x.nodes('/Employees/Employee')
e(x)
?
The query plans indicate that the cost of the first is twice the cost of the second. Is this true in practice?
Derek
March 26, 2008 at 7:29 am
just do this to retrieve the element count for the loop - we've had to do this a lot..
select @max-2 = @x.value('fn:count(/Employees/Employee)','int')
or you could even include the xpath in the while loop definition:
while @i <= (@x.value('fn:count(/Employees/Employee)','int'))
begin
print @i
set @i = @i + 1
end
there are a lot of fn: xpath functions that work really well for different situations - BOL has a listing of them, just search for "fn:"
March 26, 2008 at 7:46 am
You can retrieve all names without a CTE and CROSS APPLY as well:
DECLARE @x XML;
SET @x = '<Employees>
<Employee ID="101">
<Name>Jacob</Name>
<Department>IT</Department>
</Employee>
<Employee ID="354">
<Name>Steve</Name>
<Department>IT</Department>
</Employee>
<Employee ID="456">
<Name>Bob</Name>
<Department>IT</Department>
</Employee>
<Employee ID="478">
<Name>Joe</Name>
<Department>IT</Department>
</Employee>
<Employee ID="981">
<Name>Louis</Name>
<Department>IT</Department>
</Employee>
</Employees>';
-- select "Name"
WITH Num(i)
AS
(
SELECT 1
UNION ALL
SELECT i + 1
FROM Num
WHERE i < (SELECT @x.value('count(/Employees/Employee)','int') )
)
SELECT x.value('Name[1]', 'VARCHAR(20)')
FROM Num
CROSS APPLY @x.nodes('/Employees/Employee[position()=sql:column("i")]') e(x);
That's if you really want to use the position() function. Without using position() it gets a little simpler:
SELECT x.value('Name[1]', 'VARCHAR(20)')
FROM @x.nodes('/Employees/Employee') e(x);
March 26, 2008 at 8:08 am
This has been helpful, after I spent 0.5 day yesterday trying to figure out XQuery in T-SQL as DBA
in the end, I cast XML to VARCHAR and PATINDEX it....
Can anybody show/confirm how I can do this as SET operation on a table T with X as a XML column, instead of working on 1 XML @x at a time
e.g. can I do this to get all Names, say in a department table T that has an Employee XML column X?
SELECT x.value('Name[1]', 'VARCHAR(20)')
FROM T.X.nodes('/Employees/Employee') e(x);
Thanks in advance
I really need a quick lesson in XQuery
March 26, 2008 at 9:33 am
Sorry to be Lazy or maybe just an american?
Anyway I know there is a meaning behind this in the code.
e(x)
I just can't seem to figure out what. One of the Replies used T(c) instead. I'm sure it's some type of XML formatting paramater I just have no idea and am curious.
Thanks,
M
March 26, 2008 at 9:48 am
After the .nodes() method you must create a table and column alias. e is the table alias, c is the column alias.
March 26, 2008 at 11:11 am
This is more elegant.
SELECT
Table1.Column1.value('.','VARCHAR(20)') AS Employee_Name
FROM
@XML_Employee_Name.nodes('/Employees/Employee/Name[1]') AS Table1(Column1)
March 26, 2008 at 11:39 am
Or for this particular XML data you could simplify even further:
SELECT
Table1.Column1.value('.','VARCHAR(20)') AS Employee_Name
FROM
@XML_Employee_Name.nodes('//Name[1]') AS Table1(Column1)
March 26, 2008 at 12:03 pm
Correct. It could be simplified even more.
It comes down to coding standards, personal preference and style.
It functions and performs the same as the following.
SELECT t.c.value('.','VARCHAR(20)') AS [Name] FROM @X.nodes('//Name[1]') AS t(c)
But if I wrote code like that then I'd have to comment for it my peers and superiors. So I try to right code so it is easier to understand and some what self documenting (If there is such a thing).
March 26, 2008 at 12:28 pm
cmille19 (3/26/2008)
Another way using xquery if you have multiple Name elements as noted in this blog entryhttp://blogs.msdn.com/mrorke/archive/2005/07/21/441554.aspx
SELECT T.ref.value('.', 'varchar(256)') AS Employee
FROM
(
select [Xml]=@x.query('
for $i in data(/Employees/Employee/Name) return
element temp { $i }
')
) A
cross apply A.Xml.nodes('/temp') T(ref)
I think this is something along the lines of what I'm trying to do...
But what if I want lots of different nodes or elements?
Example XML:
SET @x= '
<CREDITREPORT CREDITREPORTID="CRRept0001" CreditReportType="Merge" MergeType="ListAndStack" EquifaxIncludedIndicator="N"
ExperianIncludedIndicator="Y" TransUnionIncludedIndicator="N">
<CreditReportIdentifier>xxxxx_xxx938</CreditReportIdentifier>
<LastUpdatedDate>2006-04-10</LastUpdatedDate>
<MERGEDLIABILITY ScoreTypeCode="Non" IndustryCode="FB" ICText="Mortgage Brokers" CollectionCode="" CollectionText=""
MERGEDLIABILITYID="xxxxx_1_12" AccountOwnershipType="Individual" AccountStatusType="Transferred" AccountType="Mortgage"
BusinessType="Finance" CreditLoanType="ConventionalRealEstateMortgage" CurrentDelinquencyRatingType="AsAgreed"
ConsumerDisputeIndicator="N" DerogatoryDataIndicator="Y" BORROWERIDREFS="">
<AccountIdentifier>******5563</AccountIdentifier>
<AccountOpenedDate>2002-01</AccountOpenedDate>
<AccountStatusDate>2002-12</AccountStatusDate>
<CreditorName>OLYMPUS</CreditorName>
<HighBalanceAmount>107200</HighBalanceAmount>
<HighCreditAmount>107200</HighCreditAmount>
<Late30DaysCount>0</Late30DaysCount>
<Late60DaysCount>0</Late60DaysCount>
<Late90DaysCount>0</Late90DaysCount>
<MonthsReviewedCount>13</MonthsReviewedCount>
<PaymentPatternData>NCCCCCCCCCCCC</PaymentPatternData>
<PaymentPatternStartDate>2002-12</PaymentPatternStartDate>
<ReportedDate>2002-12</ReportedDate>
<TermMonths>360</TermMonths>
<CREDITCOMMENT CommentSource="RepositoryBureau">
<Comment>Account transferred to another lender</Comment>
</CREDITCOMMENT>
<CREDITCOMMENT CommentSource="RepositoryBureau">
<Comment>BaseStatus code `05` - TRANSFER</Comment>
</CREDITCOMMENT>
</MERGEDLIABILITY>
</CREDITREPORT> '
What if I want to iterate through 1000 rows in SQL, with each row containing XML like this, and each XML document will have 4+ MergedLiability nodes and I want data in those nodes?
That's where I get confused on the looping stuff.
And uhh..yeah...this is a ... uhm... fictitious example...yeah...has nothing to do with my job...nothing at all...I dreamed up the complicated XML example...all by myself...sure...
March 26, 2008 at 12:38 pm
For readability purposes I'd probably go with something like this:
SELECT x.value('Name[1]', 'VARCHAR(20)')
FROM @x.nodes('/Employees/Employee') e(x);
March 26, 2008 at 1:02 pm
Mike C (3/26/2008)
For readability purposes I'd probably go with something like this:
SELECT x.value('Name[1]', 'VARCHAR(20)')
FROM @x.nodes('/Employees/Employee') e(x);
I like this method. It is actually faster and uses less resources as it applies the XPathFilter.
Thanks for the tip =)
Viewing 15 posts - 1 through 15 (of 49 total)
You must be logged in to reply to this topic. Login to reply
This website stores cookies on your computer.
These cookies are used to improve your website experience and provide more personalized services to you, both on this website and through other media.
To find out more about the cookies we use, see our Privacy Policy