I am trying to parse an XML field using SQL into a table and I need a little help starting. An example of the XML field for one row is as follows:
<MarketValueTransactionVo
objectId="104" statusCode="0" acctNum="60835733" recType="6"
errorFlag="N" sourceCode="0" userId="DATAEXCHANGE" taxItem="0"
amount="4496.79" accountEntityType="0" transactionAmount="4496.79"
importFormatType="5" dateEntered="01252015" clearingFirmBrokerCode="OPSX"
formattedAmount="$4,496.79" totalShares="0" controlNumberSequence="0"
applicableYear="2014" brokerCode="OPSX" ssn="632248334"
entityId="OPSX" entityTypeCode="4" activityApplicationCode="3001"
activityTypeCode="801" entityPresentationNumber="0" checkStatusCode="0"
correctionCode="0" correctionTypeCode="0" entityLOBCode="0"
requestPresentationNumber="0" requestStatusCode="0" reverseReasonCode="0"
loanPresentationNumber="0">
</MarketValueTransactionVo>
You want to address XML tag attributes. Tag attributes can be addressed using at-sign symbol #, see for examples Import XML with Attribute to SQL Server Table and Convert Xml to Table SQL Server (the second format in the answer):
SELECT
Tbl.Col.value('#objectId', 'int'),
Tbl.Col.value('#statusCode', 'tinyint'),
Tbl.Col.value('#acctNum', ...proper type int? varchar(xx)? ),
...
FROM #xml.nodes('//MarketValueTransactionVo') Tbl(Col)
Related
I'm trying to put together a report for a badge program. Some the data for custom fields we created are stored in a single column in the table as XML. I need to return a couple of the items in there to the report and am having a hard time getting the proper syntax to get it to parse out.
Aside from the XML, the query itself is simple:
SELECT
Person1.firstName
,Person1.lastName
,Person1.idNumber
,Person1.idNumber2
,Person1.idNumber3
,Person1.status
,Person1.customdata
FROM
Person1
the field "customdata" is the XML field that I need to pull Title, and 2 different dates out of. This is what the XML looks like:
<person1_7:CustomData xmlns:person1_7="http://www.badgepass.com/Person1_7">
<Title>IT Director</Title>
<Gaming_x0020_Level>Level 1</Gaming_x0020_Level>
<Gaming_x0020_Issue_x0020_Date>2021-02-18T12:00:00Z</Gaming_x0020_Issue_x0020_Date>
<Gaming_x0020_Expire_x0020_Date>2022-02-18T12:00:00Z</Gaming_x0020_Expire_x0020_Date>
<Betting_x0020_Level>Level 1</Betting_x0020_Level>
<Betting_x0020_Issue_x0020_Date>2021-02-18T12:00:00Z</Betting_x0020_Issue_x0020_Date>
<Betting_x0020_Expire_x0020_Date>2022-02-18T12:00:00Z</Betting_x0020_Expire_x0020_Date>
<BadgeType>Dual Employee</BadgeType>
<Gaming_x0020_Status>TEMP</Gaming_x0020_Status>
<Betting_x0020_Status>TEMP</Betting_x0020_Status>
</person1_7:CustomData>
I have tried a couple of different methods trying to follow the advice from How to query for Xml values and attributes from table in SQL Server? and then tried declaring a XML namespace with the following query:
WITH XMLNAMESPACES ('http://www.badgepass.com/Person1_7' as X)
SELECT
Person1.firstName
,Person1.lastName
,Person1.idNumber
,Person1.idNumber2
,Person1.idNumber3
,Person1.status
,Person1.customdata.value('(/X:person1_7:customdata/X:Title)[1]', 'varchar(100)') AS Title
FROM
Person1
So far all of my results keep returning "XQuery [Person1.customData.value()]: ")" was expected.
" I'm assuming I have a syntax issue that I'm overlooking as I've never had to manipulate XML with SQL before. Thank you in advance for any help.
Please try the following solution.
Notable points:
XQuery .nodes() method establishes a context so you can access any
XML element right away without long XPath expressions.
Use of the text() in the XPath expressions is for performance
reasons.
SQL
-- DDL and sample data population, start
DECLARE #person1 TABLE (firstname varchar(50), customdata xml);
INSERT INTO #person1(firstname, customdata) VALUES
('John', '<person1_7:CustomData xmlns:person1_7="http://www.badgepass.com/Person1_7">
<Title>IT Director</Title>
<Gaming_x0020_Level>Level 1</Gaming_x0020_Level>
<Gaming_x0020_Issue_x0020_Date>2021-02-18T12:00:00Z</Gaming_x0020_Issue_x0020_Date>
<Gaming_x0020_Expire_x0020_Date>2022-02-18T12:00:00Z</Gaming_x0020_Expire_x0020_Date>
<Betting_x0020_Level>Level 1</Betting_x0020_Level>
<Betting_x0020_Issue_x0020_Date>2021-02-18T12:00:00Z</Betting_x0020_Issue_x0020_Date>
<Betting_x0020_Expire_x0020_Date>2022-02-18T12:00:00Z</Betting_x0020_Expire_x0020_Date>
<BadgeType>Dual Employee</BadgeType>
<Gaming_x0020_Status>TEMP</Gaming_x0020_Status>
<Betting_x0020_Status>TEMP</Betting_x0020_Status>
</person1_7:CustomData>');
-- DDL and sample data population, end
WITH XMLNAMESPACES ('http://www.badgepass.com/Person1_7' as person1_7)
SELECT firstName
, c.value('(Title/text())[1]', 'VARCHAR(100)') AS Title
, c.value('(Gaming_x0020_Issue_x0020_Date/text())[1]', 'DATETIME') GamingIssueDate
FROM #person1
CROSS APPLY customdata.nodes('/person1_7:CustomData') AS t(c);
Output
+-----------+-------------+-------------------------+
| firstName | Title | GamingIssueDate |
+-----------+-------------+-------------------------+
| John | IT Director | 2021-02-18 12:00:00.000 |
+-----------+-------------+-------------------------+
I'm a beginner when it comes to SQL and have no experience with XML so I'm after a little bit of help.
At the moment I am looking at a single table and just using the query below
select
name,
convert(xml, convert(varbinary(max), orders)) ClientOrders
from client;
In the second columns of SQL output, I have a very lengthy bit of XML similar to the example below. I've used "..." just to skip over some of the output and give a general idea.
Name
ClientOrders
Client1
<report ... ><QueryParameter></QueryParameter Name = "#hello1"><commandtext> ...<value>Example1</value>....<value>Example2</value>...<value>Example3</value>...</commandtext></report>
Client2
<report ... ><QueryParameter></QueryParameter Name = "#hello2"><commandtext> ...<value>Example4</value>....<value>Example5</value>...<value>Example6</value>...</commandtext></report>
I have this for a lot of rows and this output is so long that it exceeds the Excel cell character limit. I'm only looking for the values Example1 through to Example6 in the example given above. Is there an SQL command I can run to get the above string between the open and close value?
I am using SSMS version 18.9.1
Cheers
I am just trying to pull the records bypassing the XML path in where the condition of SQL unfortunately I am unable to do.
Note: Pull the records bypassing input as salesteamid value. Please someone can help me to run the query without any failures.
Query :
SELECT * from activity where= ExtractValue('/ActivityId/Agent/Territory/SalesTeamId[contains(10669)]');
XML:
<Activity
xmlns="urn:astrazeneca:na:Activity:domain:3" RestrictionGroup="NONE"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="DiscussionActivityType" TransactionCode="I" CreatedOnDate="2019-11-21T16:04:29" UpdatedOnDate="2019-11-21T16:04:32" SourceCreatedByID="20303090" SourceCreatedByFirstName="Brandy" SourceCreatedByLastName="Nirider" SourceCreatedByRole="" SourceUpdatedByID="20303090" SourceUpdatedByFirstName="Brandy" SourceUpdatedByLastName="Nirider" SourceSystemCode="FSA" SystemOfRecordCode="FSA" RecordCompanyCode="AZN" SourceCountry="USA" SourceRegion="USA" SourceSystemGroup="VNA" SystemOfRecordGroup="VNA">
<ActivityId>
<ns2:ID
xmlns:ns2="urn:astrazeneca:na:CommonTypes:domain:2" SystemCode="VNA">a080P00001YZM7WQAX
</ns2:ID>
</ActivityId>
<Agent>
<EmployeeId>
<ns2:ID
xmlns:ns2="urn:astrazeneca:na:CommonTypes:domain:2" SystemCode="EMPLID">20303090
</ns2:ID>
</EmployeeId>
<Territory>
<ns2:TerritoryId
xmlns:ns2="urn:astrazeneca:na:CommonTypes:domain:2">
<ns2:ID SystemCode="AZ">20070009</ns2:ID>
</ns2:TerritoryId>
<ns2:TerritoryCode
xmlns:ns2="urn:astrazeneca:na:CommonTypes:domain:2">20070009
</ns2:TerritoryCode>
<ns2:Role
xmlns:ns2="urn:astrazeneca:na:CommonTypes:domain:2">PSS
</ns2:Role>
<ns2:Description
xmlns:ns2="urn:astrazeneca:na:CommonTypes:domain:2">Indianapolis C IN 2
</ns2:Description>
<ns2:SalesTeamId
xmlns:ns2="urn:astrazeneca:na:CommonTypes:domain:2">
<ns2:ID SystemCode="AZ">10669</ns2:ID>
</ns2:SalesTeamId>
<ns2:SalesTeamCode
xmlns:ns2="urn:astrazeneca:na:CommonTypes:domain:2">D_ALPHA
</ns2:SalesTeamCode>
</Territory>
</Agent>
<Customer>
<AZCustomerMasterID SystemCode="AZ">58586509</AZCustomerMasterID>
<SourceCustomerID SystemCode="NAVVA">001U000000pMTySIAW</SourceCustomerID>
<CustomerType>HCP</CustomerType>
<CustomerActivityRole>participant</CustomerActivityRole>
</Customer>
<ReferenceContent>
<ReferenceName>Reported Adverse Reaction</ReferenceName>
<ReferenceType>action</ReferenceType>
<ReferenceId SystemCode="VNA">Reported Adverse Reaction</ReferenceId>
</ReferenceContent>
<StartDate>2019-11-21T16:03:00</StartDate>
<EndDate>2019-11-21T16:03:00</EndDate>
<Topic>
<Name>BYDUREON BCISE</Name>
<Product>
<AZBrandId SystemCode="AZ">881574</AZBrandId>
<AZProductId SystemCode="AZ">881574</AZProductId>
<SourceProductId SystemCode=""/>
<ReferenceProductId SystemCode=""/>
<ProductName>BYDUREON BCISE</ProductName>
</Product>
</Topic>
<ActivityAction>discussion</ActivityAction>
<ActivityStatus>completed</ActivityStatus>
<ActivityInitiatedBy>AstraZeneca agent</ActivityInitiatedBy>
<ActivityOutcome>success with identified customer</ActivityOutcome>
<CommunicationMode>in person</CommunicationMode>
<LocationSetting>Selling</LocationSetting>
<SourceValues>
<Status>Submitted</Status>
<SubStatus>Completed</SubStatus>
<Applet>Actions</Applet>
<Activity>Detail Only</Activity>
<InteractionCategory>A_Selling (PSS)</InteractionCategory>
<Type>Selling</Type>
</SourceValues>
<Priority>2</Priority>
<DiscussionTool>N</DiscussionTool>
<ActivityTypeCheck>DiscussionActivityType</ActivityTypeCheck>
</Activity>
Assuming you're trying to filter on an ID within the XML, you have an issue with syntax, you've supplied the root node as ActivityId instead of Activity, you aren't going down to the ID node, you're misusing contains - and that probably isn't what you want anyway; and you're ignoring the namespaces.
This will only find rows where the XML has a specific ID:
SELECT * from activity
where ExtractValue(xml,
'/Activity/Agent/Territory/ns2:SalesTeamId/ns2:ID/text()',
'xmlns="urn:astrazeneca:na:Activity:domain:3" xmlns:ns2="urn:astrazeneca:na:CommonTypes:domain:2"'
) = 10669;
But ExtractValue has long been deprecated, so you should use XMLQuery instead. Or in this context it would probably make more sense to use XMLExists, with the value you want embeded:
SELECT * from activity
where XMLExists('
declare default element namespace "urn:astrazeneca:na:Activity:domain:3";
declare namespace ns2="urn:astrazeneca:na:CommonTypes:domain:2";
/Activity/Agent/Territory/ns2:SalesTeamId/ns2:ID[text()=10669]
'
passing xml
);
or perhaps more usefully supplied as an argument:
SELECT * from activity
where XMLExists('
declare default element namespace "urn:astrazeneca:na:Activity:domain:3";
declare namespace ns2="urn:astrazeneca:na:CommonTypes:domain:2";
/Activity/Agent/Territory/ns2:SalesTeamId/ns2:ID[text()=$id]
'
passing xml, 10669 as "id"
);
db<>fiddle
If you then want to extract specific data from the XML in matching rows then look at XMLQuery or XMLTable - but that's a separate issue.
Image I have a currency table, containing e.g. this record :
- Id = 1
- Code = EUR
- Symbol = €
Important to notice :
The input in our database is already property HTML-encoded!
Now, when I use this SQL statement :
SELECT '#id' = Currency.Id
, '#code' = Currency.Code
, '#symbol' = Currency.Symbol
FROM Currency
FOR XML PATH('currency')
, ROOT('list')
, TYPE
;
...it unfortunately results into the following XML :
<list><currency id="1" code="EUR" symbol="€" /></list>
Notice that the Euro-symbol has been re-encoded, rendering it invalid.
How can I avoid that? How can I obtain the following XML output :
<list><currency id="1" code="EUR" symbol="€" /></list>
The result you get unfortunately and is re-encoded and invalid is perfectly correct - but not what you expect. You pass in € which is a string. Within XML this is escaped as € and will be re-coded to €.
You must stop to think of XML as kind of formalized string. This is a technical issue. XML will handle this implicitly.
There are two ways:
Go the string-way and cast your XML to NVARCHAR, do any string manipulation you might want (e.g. REPLACE(myXML,'€','€') and cast back to XML or
(I'd prefer this!) hand in the € as actual symbol and let the XML engine do the encoding.
EDIT
One more thing: SQL Server doesn't know the € entity. Try with € or €:
SELECT '€' AS [#EuroSign] --works
,'€' AS [#NamedEscapedEuro] --will be encoded
,'€' AS [#EscapedEuro] --will be encoded
FOR XML PATH('TestEuro'),ROOT('root')
SELECT --CAST('<x>'+'€'+'</x>' AS XML).value('/x[1]','nvarchar(10)') AS [#EuroSign] --not allowed!!!
--CAST('<x>'+'€'+'</x>' AS XML).value('/x[1]','nvarchar(10)') AS [#NamedEscapedEuro] --not allowed, exists, but not known in SQL Server!
CAST('<x>'+'€'+'</x>' AS XML).value('/x[1]','nvarchar(10)') AS [#EscapedEuro] --works
FOR XML PATH('TestEuro'),ROOT('root')
I have a query that uses FOR XML RAW, ELEMENTS to return a SELECT query as a structured XML document. However, when I get the result using a TSQLDataSet by using Fields[0].Value, the result is different from what I see when I run the query in SQL Server Management Studio.
What I see in the result from the TSQLDataSet:
customerIdфname၄governmentNumberไdebtorAddress1ไdebtorAddress2ไdebtorAddress3ไdebtorAddress4ࡄpostCodeୄcontactNameՄphonë́faxൄcustomerSinceՄtermsلactiveไcurrentBalanceلDebtorခŁ䄁ഃӤ
What I see in the result in SSMS:
<Debtor>
<customerId>C0E449E5B2C </customerId>
<name>New Customer 2 </name>
<governmentNumber> </governmentNumber>
<debtorAddress1>Address Line 1 </debtorAddress1>
<debtorAddress4>Address Line 4 </debtorAddress4>
<postCode>1234 </postCode>
<phone>1234567890 </phone>
<fax>1234567890 </fax>
<customerSince>2013-06-10T18:16:06.213</customerSince>
<terms>M </terms>
<active>true</active>
<currentBalance>0.0000</currentBalance>
</Debtor>
Is there a particular way it should be executed to get the right result?
AFAIK this is a DbExpress limitation. I know how overcome this, but using ADO (the returned data must be requested using a special parametrized object and a set of ADO streams). However you can use a workaround converting the XML data to a string in the server side sorrounding the sentence with a select (subquery) or just using a simple CAST statement.
For example if you sentence is like so
SELECT Foo, Bar FROM FooTable FOR XML RAW, ELEMENTS
you can rewrite to
SELECT (SELECT Foo, Bar FROM FooTable FOR XML RAW, ELEMENTS)
or you can rewrite to (use a CAST VARCHAR or NVARCHAR)
SELECT CAST( (SELECT Foo, Bar FROM FooTable FOR XML RAW, ELEMENTS) AS VARCHAR(MAX))
and finally
Retrieve the result like this
SQLDataSet1.Fields[0].AsString