Home > Blockchain >  Select data using WHERE condition on XML data column in SQL table
Select data using WHERE condition on XML data column in SQL table

Time:03-12

I have a table that lists some user details.

ID GUID Username Password Data
1 a2a8s7d4d xswe xxxxxx XML
2 aer335mla user xxxxxx XML

The Data column contains data using XML. Below is a sample from the table.

<UserInfo xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ComponentFramework">
<ActiveDirectoryUser>false</ActiveDirectoryUser>
<CanUpdateMasterData>false</CanUpdateMasterData>
<CanUploadFiles>false</CanUploadFiles>
<ChangePassword>false</ChangePassword>
<CustomDataPageSize>false</CustomDataPageSize>
<CustomMasterDataPageSize>false</CustomMasterDataPageSize>
<DataPageSize>100</DataPageSize>
<Disabled>true</Disabled>
<Displayname>Pål</Displayname>
<Email i:nil="true" />
<EnforcePasswordPolicy>false</EnforcePasswordPolicy>
<EnvironmentIdList xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
<GUID i:nil="true" />
<GeoLocation>
    <City i:nil="true" />
    <Country i:nil="true" />
    <CountryCode i:nil="true" />
    <Ip i:nil="true" />
    <Isp i:nil="true" />
    <Lat>0</Lat>
    <Lon>0</Lon>
    <Org i:nil="true" />
    <Query i:nil="true" />
    <Region i:nil="true" />
    <RegionName i:nil="true" />
    <Status i:nil="true" />
    <Timezone i:nil="true" />
    <Zip i:nil="true" />
</GeoLocation>
<GroupIdList xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
<HttpLink i:nil="true" />
<JobIdList xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
<LastLoggedIn>2015-06-11T19:04:44.6407074 05:30</LastLoggedIn>
<MasterDataPageSize>1000</MasterDataPageSize>
<ModifyImages>false</ModifyImages>
<QualityControl>false</QualityControl>
<QualityControlGroupId i:nil="true" />
<Review>false</Review>
<ReviewGroupId i:nil="true" />
<SecurityToken i:nil="true" />
<ShowTrackerPage>false</ShowTrackerPage>
<StatIdList xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
<Username>&lt;new user&gt;</Username>
<Usertype>Power</Usertype>
</UserInfo>

I'm trying to match users that have their accounts disabled. Using the below sql query.

select * from [ATC_Config].[dbo].[Users] where [ATC_Config].[dbo].[Users].[Data].value('/UserInfo/Disabled[1]','nvarchar(MAX)') = 'true'

But SSMS is giving me an error Cannot call methods on nvarchar(max) and highlight my column which Data. I tried few suggestions in SO and in MSDN but nothing helped. Can someone show me what am I doing wrong?

CodePudding user response:

Because your sample XML contains a default namespace definition you'll need to declare that in your value XQuery or via with xmlnamespaces.

Here's how you can do that with value...

select *
from dbo.Users
where cast(Data as xml).value(N'
  declare default element namespace "http://schemas.datacontract.org/2004/07/ComponentFramework";
  (/UserInfo/Disabled)[1]',N'nvarchar(max)') = N'true';

Or by using with xmlnamespaces:

with xmlnamespaces(default N'http://schemas.datacontract.org/2004/07/ComponentFramework')
select *
from dbo.Users
where cast(Data as xml).value(N'(/UserInfo/Disabled)[1]', N'nvarchar(max)') = N'true';

CodePudding user response:

You need to add the namespace, and you need to cast the value to xml. This is easier if you use with because it applies to the whole query.

A slightly more efficient version of @AlwaysLearning's answer is to use exist and /text()

with xmlnamespaces (
    default N'http://schemas.datacontract.org/2004/07/ComponentFramework'
)
select *
from dbo.Users u
where cast(u.Data as xml).exist(N'/UserInfo/Disabled[text() = "true"]') = 1;

db<>fiddle

I strongly suggest you store the Data column as xml in the first place, as casting is inefficient.

  • Related