I have a table named "Table1" and in the table there are columns titled "Name" and "XMLDefinition".
Name XMLDefinition
--------------------------
Name1 xmlLink1
Name2 xmlLink2
Inside each XML an example would look similar to this below:
<Query xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<QueryView>
<QueryKey />
</QueryView>
<Description>
</Description>
<QueryFields>
<f />
<f />
</QueryFields>
<FilterFields>
<f ObjectName="TABLE5" ColumnName="ID">
<DateFilterTypes />
<FuzzyDateFilterTypes />
<MonthDayFilterTypes />
<Values>
<v>0</v>
</Values>
<TranslatedValues>
<v>No</v>
</TranslatedValues>
<DataType>Boolean</DataType>
</f>
<f ObjectName="TABLE2" ColumnName="USERID">
<DateFilterTypes />
<FuzzyDateFilterTypes />
<MonthDayFilterTypes />
<Values>
<v>B80055</v>
</Values>
<TranslatedValues>
<v>B80055</v>
</TranslatedValues>
<DataType>String</DataType>
</f>
</FilterFields>
</Query>
I'd like to return Name from TABLE1 as long as in the XML content contains where ObjectName = "TABLE2" AND ColumnName = "USERID".
I have tried the below and while it doesn't error out, it returns 0 records:
SELECT
a.Name,
X.Y.value('(f)[1]', 'VARCHAR(MAX)') as Object
FROM TABLE1 a
OUTER APPLY a.XMLDefinition.nodes('Query/FilterFields/f') as X(Y)
WHERE X.Y.value('(ObjectName)[1]', 'VARCHAR(MAX)') = 'TABLE2'
AND X.Y.value('(ColumnName)[1]', 'VARCHAR(MAX)') = 'USERID'
I'm not sure what I am missing as it seems I am drilling down from Query > FilterFields > f and I assume I'd be able to then filter based on the ObjectName and ColumnName here.
Attempt 2 Update:
SELECT Name from TABLE1
WHERE XMLDefinition.value('(/Query/QueryView/Description/QueryFields/FilterFields/f/@ObjectName) [1] ',' varchar(max)') = 'TABLE2'
AND XMLDefinition.value('(/Query/QueryView/Description/QueryFields/FilterFields/f/@ColumnName) [1] ',' varchar(max)') = 'USERID'
After trying this attempt by drilling through each tag, it is still giving me 0 results.
Attempt 3 Update:
select
a.Name,
X.Y.query(N'.') as [Object] --this returns the XML of the <f> element
from dbo.Table1 a
cross apply a.XMLDefinition.nodes('//*:f[@ObjectName="TABLE2"][@ColumnName="USERID"][1]') as X(Y);
I'm not sure why, but I tried this and now it worked and returned the results that I was looking for. I'm new to XML, but I assume this worked because it ignored all the namespaces and prior tags before the f tag?
QueryView,DescriptionandQueryFieldsare not in the path required to get to/Query/FilterFields/f- they are siblings ofFilterFields, not parents of it.//f...didn't work but//*:f...did (using a wildcard namespace) that's because thefelement isn't in the anonymous namespace like it is in the posted XML example. Wildcard namespaces can work, but they're not particularly efficient, and you sometimes get unexpected results if the same element name is declared in multiple namespaces (which is permitted).