MS SQL, Grouping, For XML, and more... need some help with this query - sql

I need your help. Sadly I don't know SQL as well as I do C# (or most other languages) and I've hit my limits with this query. This post may be a bit verbose, so I apologize for that in advance, but I want to make sure I include all the necessary info.
My goal is to create a query that selects data from SQL, groups it by a substring value of one of the columns, and outputs in XML. I'm pretty close, but I've hit a wall.
Here's an example of what it should look like:
<EXAMPLE_DATA>
<headEnd nam="AAAA">
<hardware fromDevice="ExampleDeviceAAAA" />
<hardware fromDevice="ExampleDeviceAAAA" />
<hardware fromDevice="ExampleDeviceAAAA" />
</headEnd>
<headEnd nam="BBBB">
<hardware fromDevice="ExampleDeviceBBBB" />
<hardware fromDevice="ExampleDeviceBBBB" />
<hardware fromDevice="ExampleDeviceBBBB" />
</EXAMPLE_DATA>
As you can see, the last four characters of the fromDevice are what define my headEnd groupings... here's what I'm able to return right now:
<EXAMPLE_DATA>
<headEnd nam="[headendId]">
<hardware fromDevice="ExampleDeviceAAAA" headendId="AAAA" />
<hardware fromDevice="ExampleDeviceAAAA" headendId="AAAA" />
<hardware fromDevice="ExampleDeviceAAAA" headendId="AAAA" />
<hardware fromDevice="ExampleDeviceBBBB" headendId="BBBB" />
<hardware fromDevice="ExampleDeviceBBBB" headendId="BBBB" />
<hardware fromDevice="ExampleDeviceBBBB" headendId="BBBB" />
</EXAMPLE_DATA>
And finally, here's the code I have that returns the XML above:
SELECT
'[headendID]' as "#nam"
, (
SELECT hardware.Name as "#fromDevice", RIGHT(hardware.Name, 4) as "#headendId"
FROM tblHardware AS hardware
GROUP BY RIGHT(hardware.Name, 4), hardware.Name
for xml path ('hardware') , type
)
for xml path ('headEnd'), root ('EXAMPLE_DATA')
I've removed a lot of non-essential columns to try and make this post a bit easier to read.
So, looking at what I need the XML to look like, is it even possible? I guess anything's possible... but in this case I'm completely stumped.
Thanks for reading!
EDIT: To make sure my question is clear, what I need is for the SQL code to output XML data grouped by the substring query of hardware.Name. I'm trying to make the output look like the first XML block above.

Here you go:
SELECT
RIGHT(categ.Name, 4) as "#nam" ,
(
SELECT hardware.Name as "#fromDevice"
FROM tblHardware AS hardware
WHERE RIGHT(categ.Name, 4) = RIGHT(hardware.Name, 4)
for xml path ('hardware') , type
)
FROM tblHardware as categ
GROUP BY RIGHT(categ.Name, 4)
for xml path ('headEnd'), root ('EXAMPLE_DATA')

Related

SQL XML Node Extraction

I am relatively new to work with XML data in SQL so please forgive any "silly" mistakes :p.
In essence what I am trying to do is, extract the "Before" & "After" values from the following XML:
<AuditData>
<Field Name="BrandEmailSubscribed">
<Before Value="True" />
<After Value="False" />
</Field>
<Metadata Type="OperatorInstigated">
<Note></Note>
</Metadata>
</AuditData>
I have tried using the following SQL however this is returning a blank value (not NULL though).
select top 10 C.B.value('(Before)[1]','VARCHAR(100)'),AD.* from Table AD
OUTER APPLY AD.Data.nodes('AuditData/Field') AS C(B)
Any help is much appreciated :).
You need to specify the attribute to be extracted
select top 10 C.B.value('(Before/#Value)[1]','VARCHAR(100)'), AD.*
from Table AD
OUTER APPLY AD.Data.nodes('AuditData/Field') AS C(B)

insert into statament java jstl tag

<sql:update dataSource="${applicationScope.oracleDataSource}"
var="count">
insert into books(ID,TITLE,AUTHOR,PRICE) where=user_id = <c:out value='${sessionScope.userID}'/> values(book_id_seq.nextval,title,author,price)
<sql:param value="${param.title}" />
<sql:param value="${param.author}" />
<sql:param value="${param.price}" />
</sql:update>
I have books tables. I also have the users table. I want to register their own books for each logged in user. However, I could not write the necessary query to save the book.I would be grateful if you could help with the correct query.

Extracting Text Values from XML in SQL

I'm working with SQL data hosted by a 3rd party, and am trying to pull some specific information for reporting. However, some of what I need to parse out is in XML format, and I'm getting stuck. I'm looking for the syntax to pull the text= values only from the XML code.
I believe the code should something like this, but most of the examples I can find online involve simpler XML hierarchy's than what I'm dealing with.
<[columnnameXML].value('(/RelatedValueListBO/Items/RelatedValueListBOItem/text())[1]','varchar(max)')>
Fails to pull any results. I've tried declaring the spacenames as well, but again...I only ever end up with NULL values pulled.
Example XML I'm dealing with:
<RelatedValueListBO xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://tempuri.org/RelatedValueListBOSchema.xsd">
<Items>
<RelatedValueListBOItem groupKey="Response1" text="Response1" selected="true" />
<RelatedValueListBOItem groupKey="Response2" text="Response2" selected="true" />
<RelatedValueListBOItem groupKey="Response3" text="Response3" selected="true" />
</Items>
</RelatedValueListBO>
Ideally I'd like to pull response1; response2; response3 into a single column. Allowing for the fact that multiple responses may exist. I believe I'm getting stuck with the basic code I've been trying due to the namespaces associated to RelatedValueListBO and the fact that what I want is grouped in groupKey, text, and selected, instead of the value I want just being under the Items node.
You have the namespaces defined in your XML, so you need to define them in the XQuery too.
Fast and dirty method is to replace all namespaces with a "*":
SELECT #x.value('(/*:RelatedValueListBO/*:Items/*:RelatedValueListBOItem/#text)[1]','varchar(max)')
To get all responses in a single column you can use:
SELECT
Item.Col.value('./#text','varchar(max)') X
FROM #x.nodes('/*:RelatedValueListBO/*:Items/*:RelatedValueListBOItem') AS Item(Col)
If you need a better performance, you may need to define namespaces properly.
You can use something like this to extract the value of "text" in the first node of RelatedValueListBOItem
SELECT extractvalue(value(rs), '//RelatedValueListBOItem[1]/#text')
FROM TABLE (xmlsequence(extract(sys.xmltype('<RelatedValueListBO>
<Items>
<RelatedValueListBOItem groupKey="Response1" text="Response1"
selected="true" />
<RelatedValueListBOItem groupKey="Response2" text="Response2"
selected="true" />
<RelatedValueListBOItem groupKey="Response3" text="Response3"
selected="true" />
</Items>
</RelatedValueListBO>'),'/RelatedValueListBO/Items'))) rs;

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.

In SQL how to form an XML output with one of attribute value as XML without <,> encoded

I am trying for a query which returns and XML output which has one of the attribute value as XML without <, /> encoded.
Example:
<Event EventLogId="124018" EventCategoryCode="ABC"
EventTypeCode="ERROR"
xmlObject="<attributes><attribute>A1</attribute></attributes>" />
<Event EventLogId="124019" EventCategoryCode="DEF"
EventTypeCode="Warning"
xmlObject="<attributes><attribute>A2</attribute></attributes>" />
I tried this query
SELECT
EventLogId AS EventLogId
,EventCategoryCode AS EventCategoryCode
,EventTypeCode AS EventTypeCode
,CAST(Event.xmlObject AS NVARCHAR(MAX)) as xmlObject
FROM
EventLog Event (NOLOCK)
FOR XML AUTO
But I am getting this output
<Event EventLogId="124018" EventCategoryCode="ABC"
EventTypeCode="ERROR"
xmlObject="<attributes><attribute>A1</attribute></attributes>" />
<Event EventLogId="124019" EventCategoryCode="DEF"
EventTypeCode="Warning"
xmlObject="<attributes><attribute>A2</attribute<</attributes>" />
I want <, /> in place of < and >
It is not valid to have non-escaped (i.e. not entity encoded) characters in attributes or anywhere in XML.
To be 100% accurate, before I get lots of comments, you can use the special DATA syntax, but that is not legal in an attribute. Also it is rare to see this feature used.
You can read the standard here (http://www.w3.org/TR/xml/) The base XML standard is actually quite short and should take you less than an hour to read.