Export SQL XML field to grid [duplicate] - sql

I have something like the following XML in a column of a table:
<?xml version="1.0" encoding="utf-8"?>
<container>
<param name="paramA" value="valueA" />
<param name="paramB" value="valueB" />
...
</container>
I am trying to get the valueB part out of the XML via TSQL
So far I am getting the right node, but now I can not figure out how to get the attribute.
select xmlCol.query('/container/param[#name="paramB"]') from LogTable
I figure I could just add /#value to the end, but then SQL tells me attributes have to be part of a node. I can find a lot of examples for selecting the child nodes attributes, but nothing on the sibling atributes (if that is the right term).
Any help would be appreciated.

Try using the .value function instead of .query:
SELECT
xmlCol.value('(/container/param[#name="paramB"]/#value)[1]', 'varchar(50)')
FROM
LogTable
The XPath expression could potentially return a list of nodes, therefore you need to add a [1] to that potential list to tell SQL Server to use the first of those entries (and yes - that list is 1-based - not 0-based). As second parameter, you need to specify what type the value should be converted to - just guessing here.
Marc

Depending on the the actual structure of your xml, it may be useful to put a view over it to make it easier to consume using 'regular' sql eg
CREATE VIEW vwLogTable
AS
SELECT
c.p.value('#name', 'varchar(10)') name,
c.p.value('#value', 'varchar(10)') value
FROM
LogTable
CROSS APPLY x.nodes('/container/param') c(p)
GO
-- now you can get all values for paramB as...
SELECT value FROM vwLogTable WHERE name = 'paramB'

Related

Extract data from XML string in Hive Table without using XPath

I am trying to use a view to extract a string(value) from a large XML string that sits in a single column in a hive table. I need to get the associated FOO_STRING_VALUE for COMPANY_ID, SALE_IND, and CLOSING_IND.
<Message>
<Header>
<FOO_STRING>
<FOO_STRING_NAME>COMPANY_ID</FOO_STRING_NAME>
<FOO_STRING_VALUE>44-1235</FOO_STRING_VALUE>
</FOO_STRING>
<FOO_STRING>
<FOO_STRING_NAME>SALE_IND</FOO_STRING_NAME>
<FOO_STRING_VALUE>Y</FOO_STRING_VALUE>
</FOO_STRING>
<FOO_STRING>
<FOO_STRING_NAME>CLOSING_IND</FOO_STRING_NAME>
<FOO_STRING_VALUE>Y</FOO_STRING_VALUE>
</FOO_STRING>
</Header>
</Message>
The XML file can have up to 50 "FOO_STRINGS" and there is no guarantee in what order they will be in so I can not use XPATH unless I have 50 xpath_string calls for each Name/Value pair and matched them up later. I am using xpath like this .....
xpath_string(xml_txt, '/Message/Header/FOO_STRING[1]/FOO_STRING_VALUE') AS String_Val_1
xpath_string(xml_txt, '/Message/Header/FOO_STRING[2]/FOO_STRING_VALUE') AS String_Val_2
xpath_string(xml_txt, '/Message/Header/FOO_STRING[3]/FOO_STRING_VALUE') AS String_Val_3
However, if the order changes than it doesn't work. I'm wondering if there is a quick way to get to find the FOO_STRING_NAME needed the and get the corresponding Value using regexp_extract() or some other way? I am not familiar with Regex so any help or suggestions would be helpful, Thank you a ton
" if the order changes than it doesn't work "
Don't use position, then.
xpath_string(xml_txt, '/Message/Header/FOO_STRING[FOO_STRING_NAME="COMPANY_ID"]/FOO_STRING_VALUE') AS String_Val_1
xpath_string(xml_txt, '/Message/Header/FOO_STRING[FOO_STRING_NAME="SALE_IND"]/FOO_STRING_VALUE') AS String_Val_2
xpath_string(xml_txt, '/Message/Header/FOO_STRING[FOO_STRING_NAME="CLOSING_IND"]/FOO_STRING_VALUE') AS String_Val_3

Check if XML nodes are empty in SQL

Hi I am new to XML manipulation, my question would be if there is a possibility of detecting if the XML node is an empty node like this: <gen:nodeName />
I am able to manipulate single nodes however I would be interested if there is an approach like a loop or recursive function that could save some time doing manual labor looking trough every single node. I have no idea how to approach this problem though.
Thanks for help.
You did not specify the dialect of SQL ([sql] is not enough, please specify always the RDBMS incl. version).
This is for SQL-Server, but the semantics should be the same.
DECLARE #xml XML=
N'<root>
<SelfClosing />
<NoContent></NoContent>
<BlankContent> </BlankContent>
<HasContent>blah</HasContent>
<HasContent>other</HasContent>
</root>';
SELECT #xml.query(N'/root/*') AS AnyBelowRoor --All elements
,#xml.query(N'/root/*[text()]') AS AnyWithTextNode --blah and other
,#xml.query(N'/root/*[not(text())]') AS NoText --no text
,#xml.query(N'/root/*[text()="blah"]') AS AnyWithTextNode--blah only
The <SelfClosing /> is semantically the same as the <NoContent><NoContent>. There is no difference.
It might be a surprise, but a blank as content is taken as empty too.
So the check for empty or not empty is the check for the existance of a text() node. one can negate this with not() to find all without a text().
Interesting: The result for NoText comes back as this (SQL-Server)
<SelfClosing />
<NoContent />
<BlankContent />
The three elements are implicitly returned in the shortest format.

Using a variable in a SQL Server 2005 stored procedure with XQuery

I'm working with the following XML
<AEDControl ControlGU="17fed98c-8128-4c6b-9b50-3dbe73889b9d"
ControlLabel="Posting Status"
TypeGU="6b4d08b1-6340-450c-beae-517b7d84e717"
ControlDescription="">
<Elements>
<Element ElementGU="2da346d1-2e05-4aa3-9bae-5aa9b3b75d5c"
Label="Active"
IsDefault="false"/>
<Element ElementGU="fa8966fc-c796-4482-9ee1-f619910dc86e"
Label="Closed"
IsDefault="false"/>
<Element ElementGU="d701a7d7-c3bd-496b-8d4b-b854a6937c3a"
Label="Filled"
IsDefault="false"/>
<Element ElementGU="75af1941-f14f-4b7e-9f1e-5b6852c4a4f7"
Label="New"
IsDefault="false"/>
<Element ElementGU="aa54e387-608e-4758-b4f2-c1dc485a5576"
Label="Pending"
IsDefault="true"/>
<Element ElementGU="210aef5c-e4cf-4987-815f-0e4274b45e08"
Label="Scratch"
IsDefault="false"/>
</Elements>
I'm trying to query from a stored procedure to pull back a label on the element that has a specific ElementGU
My stored procedure looks like this:
SELECT
CAST(CONTROL_XML.query('data(/AEDControl/Elements/Element/#Label)') as varchar(100)) as ControlLabel
FROM
Control
WHERE
CONTROL_XML.exist('/AEDControl/Elements/Element[#ElementGU = sql:variable("#SelectedValueGU")]') = 1
where ElementGU is a passed in uniqueidentifier field.
I appear to be having no luck with this. I've read that you can't do this kind of dynamic query with XQuery, but at the same time, the slq:variable() call is part of XQuery, so is there anyone out there that can clear this up to me?
I'm still fairly new on the XQuery front.
You need to approach this a bit differently: since you have a list of <Element> nodes, I would suggest you create a list of nodes and then pick the right one from that list - something like this:
SELECT
AED.Element.value('(#Label)[1]', 'varchar(100)') as ControlLabel
FROM
Control
CROSS APPLY
Control_XML.nodes('/AEDControl/Elements/Element') AS AED(Element)
WHERE
AED.Element.value('(#ElementGU)[1]', 'uniqueidentifier') = #SelectedValueGU
I don't know how you want to select from your base table - whether you want to have a WHERE clause or something - but the CROSS APPLY basically takes the XML field and creates a "pseudo-table" called AED.Element from the nodes given in the XPath expression, and cross-applies those to the base table. So now, for each entry in Control and each <Element> node in those rows, you get one row of data.
In that row, you can now pick out those rows where the #ElementGU value corresponds to the value you passed in, and for those XML nodes where this is the case, you then select the value of the #Label attribute
I think this XPath (with sql:variable() extension function) should work:
/AEDControl
/Elements
/Element[#ElementGU = sql:variable("#SelectedValueGU")]
/#Label

How to get required XML element from not well formed XML data in SQL server

In my SQL 2008 database table, I have one column name AUTHOR that contains XML data. The XML is not well formed and has data like below
<Author>
<ID>172-32-1176</ID>
<LastName>White</LastName>
<FirstName>Johnson</FirstName>
<Address>
<Street>10932 Bigge Rd.</Street>
<City>Menlo Park</City>
<State>CA</State>
</Address>
</Author>
Some XML have all of above data and some have just one tag.
<ID>172-32-1176</ID>
I want to write query that returns me a column as identiry.
I tried using AUTHOR.query('data(/Author/ID)') as identity but it fails when XML does not have Author node.
Thanks,
Vijay
Have you tried something like /Author/ID|/ID ? i.e. try for the first scenario, and with no match, the second ?
(note that the | operator is a set union operator, as described here)
In case that nothing "certain" can be maintained about the XML, except that a unique ID element contains the required identity value, then the following XPath expression selects the ID element:
//ID

XPath to search for elements in a sequence

With xml like:
<a>
<b>
<c>1</c>
<c>2</c>
</c>3</c>
</b>
I'm trying to create an xpath expression (for a postgresql query) that will return if is a particular value and not that is all three values. What I currently have (which does not work) is:
select * from someTable where xpath ('//uim:a/text()', job, ARRAY[ ARRAY['uim','http://www.cmpy.com/uim'] ])::text[] IN (ARRAY['1','3']);
If I try with ARRAY['1'] this will not return any values but with ARRAY['1','2','3'] it will return all three.
How can I select based on a single element in a sequence?
Thanks.
If you're asking how to get the value of a 1 or more XML elements within your XML segment the easiest way is likely to simply utilize a custom SQL CLR library and XPath analysis from within it to assemble and return whatever information you desire. At least that would be my approach.