Select data using WHERE condition on XML data column in SQL table - sql

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><new user></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?

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';

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

Unable to extract details from an XML column of MSSQL

I am new to extracting data from XML column using SQL, I did try with other simple format but this one is a bit tricky.
XML column name is "Data" and below is the value.
<SpecificationDataDto
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.datacontract.org/2004/07/Dummy.Sample.API.TransferObjects.Dto">
<Narratives>
<AnswerDto>
<AddressData />
<AddressResponseType i:nil="true" />
<Answers
xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d4p1:string>Loose Print</d4p1:string>
</Answers>
<ComponentOrderNumber>3</ComponentOrderNumber>
<Index>0</Index>
<IsQuantity>false</IsQuantity>
<MasterQuestionId i:nil="true" />
<MasterQuestionTitle i:nil="true" />
<MasterQuestionTitleResourceKey i:nil="true" />
<ParentQuestionGroupId i:nil="true" />
<ParentQuestionGroupIndex i:nil="true" />
<ParentQuestionGroupTitle i:nil="true" />
<PermutationId>65922bf8-6468-40f2-967c-27547412ba2b</PermutationId>
<PermutationOrder>0</PermutationOrder>
<ProductSpecificationLabel />
<ProductSpecificationLabelResourceKey>65A4E3D8-9FF7-48D9-B3F8-0E2D4D23A1B8</ProductSpecificationLabelResourceKey>
<QuestionGroupId i:nil="true" />
<QuestionGroupIndex i:nil="true" />
<QuestionGroupOrderNumber i:nil="true" />
<QuestionGroupTitle i:nil="true" />
<QuestionId>e575d4ac-5dfb-4170-c5c0-08da85c9a9ed</QuestionId>
<QuestionOrderNumber>1</QuestionOrderNumber>
<QuestionTitle>Product category</QuestionTitle>
<QuestionTitleResourceKey>81B4FFBC-4503-4E48-83C0-17FBB227384B</QuestionTitleResourceKey>
<ResponseIds
xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d4p1:guid>c4ed5170-6634-4aad-c054-08da7f653c36</d4p1:guid>
</ResponseIds>
<UpdateDate i:nil="true" />
</AnswerDto>
</Narratives>
</SpecificationDataDto>
I tried below but no luck
WITH XMLNAMESPACES ('http://schemas.microsoft.com/2003/10/Serialization/Arrays' AS d4p1)
, CTE as (
SELECT Order
,t.c.value('(*/QuestionTitle)[1]', 'Varchar(250)') AS Question
,t.c.value('(*/d4p1:string)[1]', 'Varchar(250)') AS Answer
FROM SchemaName.DatabaseName.TableName
CROSS APPLY Data.nodes('*/SpecificationDataDto/Narratives/AnswerDto') t(c)
WHERE Order = '737B4994'
)
select * from CTE
I am expecting the below values to come out for this order in 2 columns,
QuestionTitle = Product category
d4p1:string = Loose Print

Insert XML Data Into SQL Table with Foreign Keys

I have this XML File (there is data, but I deleted it for a purpose):
<NIACList>
<NIAC>
<Number></Number>
<SubmissionDate></SubmissionDate>
<ExpirationDate />
<IssuerIDNO></IssuerIDNO>
<IssuerName></IssuerName>
<SuspensionPeriod/>
<Cessation>
<Basis />
<Date />
</Cessation>
<Merchant>
<IDNx></IDNx>
<Name></Name>
<Address>
<Region></Region>
<Locality></Locality>
<Street></Street>
<House></House>
<Block />
<Flat />
<Phone />
<Fax />
<Email />
</Address>
</Merchant>
<CommercialUnit>
<IDNx />
<Name />
<Type></Type>
<Area></Area>
<Location></Location>
<Address>
<Region></Region>
<Locality></Locality>
<Street></Street>
<House></House>
<Block />
<Flat />
</Address>
<Activities>
<Activity>
<Code></Code>
<Name></Name>
</Activity>
</Activities>
<Goods>
<Good>
<Name></Name>
</Good>
</Goods>
<WorkProgram />
<PublicSupplyUnit>
<Capacity />
<TerraceCapacity />
</PublicSupplyUnit>
<TradingAlcohol />
<TradingBeer />
<TradingTobaccoProducts />
<AmbulatoryTrading />
<MobileUnitTrading></MobileUnitTrading>
<MobileUnit>
<Type />
<Length />
<Width />
<Height />
</MobileUnit>
<CommercialApparatusTrading></CommercialApparatusTrading>
<CommercialApparatus>
<Count />
<Length />
<Width />
<Height />
</CommercialApparatus>
</CommercialUnit>
<Modifications />
</NIAC>
</NIACList>
My task is to insert all XML data from this file into SQL Tables (SQL Server). I've inserted in most of the tables data, but here it is a problem. I have tables Address and Merchant. The first table doesn't have a foreign key, but the second table contains one, named IdAddress, so they could be relational. Is it possible to insert data into Merchant, so for each record from table Address will be linked with the IdAddress from Merchant.
Any help will be appreciated.
You need to insert the XML data in a buffer table - for example #temporary table. Then, first get the unique values that can be referred by the foreign key. Insert the one that do not exists. After that, join the #temporary table with the referenced table by the value and insert the value ID rather then the value.

SQL XML load with OpenRow

I am trying to load a XML document (below is an example of how I receive the files. I can read the xml, but I am unable to insert the the data into tables. Any help would be appreciative.
<xml xmlns:dt="urn:dt" xmlns:msxsl="urn:schemas-microsoft-com:xslt" dateofservice="1/1/2016 10:00" mmsid="201599999999" userid="dxxxxx9-xxx0-xxdb-xxx0-e8xxxxxxbcd" npid="dfxxxxx9-6xx0-xxxx-bxx0-exxxc1xxxxxd" surveyid="xxxxxxx-xxxa-exxx-8xxx-xxxx56xxxxefb" memberid="sqlsrfr">
<response qid="801" debug="7" value="H" element="select" />
<response qid="150" debug="8" value="Surfer" element="input" mapfield="lastname" />
<response qid="109" debug="9" value="Sequel" element="input" mapfield="firstname" />
<response qid="57" debug="11" value="01/01/1901" element="input" mapfield="dob" />
<response qid="56" debug="12" value="M" element="input" type="radio" aid="85" />
<response qid="78" debug="13" value="123 Sequel Lane" element="textarea" mapfield="addr1" />
<response qid="126" debug="39" value="Stuff" element="input" row="9" placeholder="Placeholder Desc" customtype="disabled" />
<response qid="128" debug="40" value="Stuff" element="input" row="9" placeholder="Placeholder Desc" customtype="disabled" />
<response qid="305" debug="41" value="More words" element="input" row="9" placeholder="Placeholder Desc" customtype="normal" />
<response qid="579" debug="330" value="1" element="input" type="radio" />
<response qid="580" debug="331" value="1" element="input" type="radio" />
<response qid="716" value="Words for value" calc="1" screening="1" />
<response qid="779" value="More words for value" calc="1" highriskdrug="1" />
- <surveyevents>
<event name="Event Name 2.0.3.7" time="1451495565657" count="1" />
<event name="s2" time="1451495568305" count="2" last="1451495728416" />
<event name="s3" time="1451495577298" count="1" />
<event name="s18" time="1451495601418" count="1" />
<event name="Event Name 2.0.3.7" time="1451495725279" count="1" />
<event name="Event Name 2.0.4.1" time="1453394485181" count="1" />
</surveyevents>
<recapturedata />
</xml>
Given, that you manage to read the XML into a variable, the full (de-normalized) query is this:
You will have to design three tables for MetaData, ResponseData and EventData and insert your data there.
If you need to create kind of IDs have a look on ROW_NUMBER() OVER()
btw: The declared namespaces are not used... and define the fitting datatypes yourself (I took only varchar(max) or int).
WITH XMLNAMESPACES('urn:dt' AS dt
,'urn:schemas-microsoft-com:xslt' AS msxsl)
,MetaData AS
(
SELECT #xml.value('/xml[1]/#dateofservice','varchar(max)') AS md_DateOfService
,#xml.value('/xml[1]/#mmsid','varchar(max)') AS md_MmsID
,#xml.value('/xml[1]/#userid','varchar(max)') AS md_UserID
,#xml.value('/xml[1]/#npid','varchar(max)') AS md_NpID
,#xml.value('/xml[1]/#surveyid','varchar(max)') AS md_SurveyID
,#xml.value('/xml[1]/#memberid','varchar(max)') AS md_MemberID
,#xml.query('.') AS XMLNode
)
SELECT md.md_DateOfService
,md.md_MmsID
,md.md_UserID
,md.md_NpID
,md.md_SurveyID
,md.md_MemberID
,response.value('#qid','int') AS resp_qID
,response.value('#debug','int') AS resp_Debug
,response.value('#value','varchar(max)') AS resp_Value
,response.value('#element','varchar(max)') AS resp_Element
,response.value('#row','int') AS resp_Row
,response.value('#mapfield','varchar(max)') AS resp_MapField
,response.value('#type','varchar(max)') AS resp_Type
,response.value('#aid','int') AS resp_aID
,response.value('#placeholder','varchar(max)') AS resp_Placeholder
,response.value('#customtype','varchar(max)') AS resp_CustomType
,EventRow.value('#name','varchar(max)') AS evnt_Name
,EventRow.value('#time','varchar(max)') AS evnt_Time
,EventRow.value('#count','int') AS evnt_Count
,EventRow.value('#last','varchar(max)') AS evnt_Last
FROM MetaData AS md
CROSS APPLY md.XMLNode.nodes('/xml/response') AS One(response)
CROSS APPLY md.XMLNode.nodes('/xml/surveyevents/event') AS The(EventRow)

How to get value from XML in stored procedure?

Can you all help me for this problem?
I want to get value from following XML in sql stored procedure. I don't get vlaue if 'xsi:type="ActiveDirectoryItem"' is in tag 'anyType', and 'ActiveDirectoryItems' tag is also with URLs. How can i do to get only values?
<?xml version="1.0" encoding="utf-8" ?>
<ActiveDirectoryItems xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
<Items>
<anyType xsi:type="ActiveDirectoryItem">
<FirstName />
<MiddleInitial />
<LastName />
<DisplayName>Migrate-group</DisplayName>
<UserPrincipalName />
<PostalAddress />
<ResidentialAddress />
<Title />
<HomePhone />
<OfficePhone />
<Mobile />
<Fax />
<Email>Migrate-group#gmail.com</Email>
<Url />
<AccountName>Migrate-group</AccountName>
<DistinguishedName />
<IsAccountActive>false</IsAccountActive>
<ManagedBy />
<Manager />
<CompareType>0</CompareType>
<Description />
<Department />
<Company />
<Type />
</anyType>
</Items>
<GlobalCatalog />
</ActiveDirectoryItems>
The format i want to get is as the following:
DisplayName Email Account Name
Migrate-group Migrate-group#gmail.com Migrate-group
you can use the value keyword
Example:
DECLARE #MyXml XML = '<Root><SomeData>100</SomeData></Root>'
DECLARE #Something INT
SELECT #Something = #MyXml.value('(//Root/SomeData)[1]', 'INT')

sp_xml_preparedocument go with error "Only one top level element is allowed in an XML document"

I'am trying to execute sp_xml_preparedocument and geting error "Only one top level element is allowed in an XML document"
my T-SQL commands:
DECLARE #aa XML
DECLARE #idoc int
SET #aa =(select * from db_name for xml auto, xmldata)
#aa now is
<Schema xmlns="urn:schemas-microsoft-com:xml-data" xmlns:dt="urn:schemas-microsoft-com:datatypes" name="Schema7">
<ElementType name="Person" content="empty" model="closed">
<AttributeType name="preson_id" dt:type="i4" />
<AttributeType name="Name" dt:type="string" />
<AttributeType name="Surname" dt:type="string" />
<AttributeType name="guid" dt:type="uuid" />
<AttributeType name="version" dt:type="bin.base64" />
<attribute type="preson_id" />
<attribute type="Name" />
<attribute type="Surname" />
<attribute type="guid" />
<attribute type="version" />
</ElementType>
</Schema>
<Person xmlns="x-schema:#Schema7" preson_id="1" Name="Иван" Surname="Иванов" guid="2E739E87-3CA4-4ED8-ADD0-8B59957668B8" version="AAAAAAAAB9E=" />
<Person xmlns="x-schema:#Schema7" preson_id="2" Name="Николай" Surname="Николаев" guid="BDC41C59-D70F-4B70-954E-4918B9516AF8" version="AAAAAAAAB9I=" />
<Person xmlns="x-schema:#Schema7" preson_id="3" Name="Максим" Surname="Максимов" guid="740E57F3-56BA-48B8-92AF-978D7B1D2712" version="AAAAAAAAB9M=" />
EXEC sp_xml_preparedocument #idoc OUTPUT, #aa
The XML parse error 0xc00ce555 occurred on line number 1, near the XML text ""
Msg 6602, Level 16, State 2, Procedure sp_xml_preparedocument, Line 1
The error description is 'Only one top level element is allowed in an XML document
I'am new in this, and i need help)))
An one more question - How parse timestamp type?
if i use
SET #aa =(select * from db_name for xml elements, root('root'), type)
sp_xml_preparedocument works fine, OPENXML returns all values of my db_table, but timestamp values looks not the same as were..
Sorry for my bad English
SELECT #aa returns
<Schema xmlns="urn:schemas-microsoft-com:xml-data" xmlns:dt="urn:schemas-microsoft-com:datatypes" name="Schema7">
<ElementType name="Person" content="empty" model="closed">
<AttributeType name="preson_id" dt:type="i4" />
<AttributeType name="Name" dt:type="string" />
<AttributeType name="Surname" dt:type="string" />
<AttributeType name="guid" dt:type="uuid" />
<AttributeType name="version" dt:type="bin.base64" />
<attribute type="preson_id" />
<attribute type="Name" />
<attribute type="Surname" />
<attribute type="guid" />
<attribute type="version" />
</ElementType>
</Schema>
<Person xmlns="x-schema:#Schema7" preson_id="1" Name="Иван" Surname="Иванов" guid="2E739E87-3CA4-4ED8-ADD0-8B59957668B8" version="AAAAAAAAB9E=" />
<Person xmlns="x-schema:#Schema7" preson_id="2" Name="Николай" Surname="Николаев" guid="BDC41C59-D70F-4B70-954E-4918B9516AF8" version="AAAAAAAAB9I=" />
<Person xmlns="x-schema:#Schema7" preson_id="3" Name="Максим" Surname="Максимов" guid="740E57F3-56BA-48B8-92AF-978D7B1D2712" version="AAAAAAAAB9M=" />
An XML document must have one root element only - see W3C specification.
Thus in you case if Schema is the root element you cannot add the Person elements at the end
Make sure that there is no duplicate entries for the record that you are trying to get