get distinct dates of timestamp elements in Basex with xquery - xquery

I have the following xml format
<root>
<node1>
<timestamp>2016-05-16T00:57:30.889</timsetamp>
</node1>
<node1>
<timestamp>2016-05-18T00:57:30.889</timsetamp>
</node1>
....
</root>
how can I get the distinct dates(for example 2016-05-16,2016-05-18)?

If you just need the dates, you can use XPath, casts and fn:distinct-values():
distinct-values(//timestamp/xs:date(xs:dateTime(.)))

Related

XQuery - to insert splitted nodes data into another node

<?xml version="1.0" encoding="UTF-8"?>
<Data>
<A><DelInfo>123-20150308-345</DelInfo><OrderNo>11</OrderNo></A>
<A><DelInfo>1204-20150308-355</DelInfo><OrderNo>15</OrderNo></A>
<A><DelInfo>153-20150408-343</DelInfo><OrderNo>10</OrderNo></A>
<A><DelInfo>44345-20150308-341</DelInfo><OrderNo>21</OrderNo></A>
<A><DelInfo>153-20150204-245</DelInfo><OrderNo>1</OrderNo></A>
<A><DelInfo>423-20150311-445</DelInfo><OrderNo>13</OrderNo></A>
..........
</Data>
I receive following XML. The DelInfo node contains a combination of
EmpId, Delivery Date and Receipt No. The OrderNo node contains the
order number wrt the Delivery Information.
The XML is stored in BaseX and I need following report to be generated from the
above XML.
<A><DelInfo>123-20150308-345</DelInfo><OrderNo>11</OrderNo><Report>20150308 - 11</Report></A>
.....
In other word, I want to insert an additional node Report with Date and Order No.
Any idea?
Replace yourdoc with your document name.
for $x in doc('yourdoc')//A
let $d := substring-before(substring-after($x/DelInfo, "-"), "-")
let $o := $x/OrderNo/text()
let $i := <C>{concat($d, " - ", $o)}</C>
return
insert node $i after $x/OrderNo
The inner substring-after() will return the string after the first -. Then, the substring-before() will return the string before the -. This way you will get the Date portion.

Invoking database using xquery giving duplicate values

I am using a XQuery to query database in an OSB project. Consider the
following table:
userId Name Category
------ ------- --------
1 Dheepan Student
2 Raju Student
and the XQuery
let $userName:=fn-bea:execute-sql(
$dataSourceJndiName,
xs:string("NAME"),
xs:string("select NAME from USER where CATEGORY= 'Student'")
)/*:NAME[1]
return <root> {data($userName)} </root>
For this query I am getting the result as <root>Dheepan Raju</root>. But I
need to return only one row even the query returns more than one row like the
following <root>Dheepan</root>. I have used predicate [1] in the query but
no clue why it concatenates the values and returning. Can anybody tell me how
to return only the first row when more than one row is returned.
You need to use proper paranthesis:
let $userName:=(fn-bea:execute-sql(
$dataSourceJndiName,
xs:string("NAME"),
xs:string("select NAME from USER where CATEGORY= 'Student'")
)/*:NAME)[1]
return <root> {data($userName)} </root>

how to save multiple rows in SQL using XML?

I have following XML, and i wish to save its data in my SQL table. I have a table named as tblDummy it has three columns "JobID" "ItemID" "SubitemID". there can be multiple subitemsid for particular combination of Jobid and Itemid. How can i do this?
<jobs>
<job>
<jobid>4711</jobid>
<items>
<itemid>1</itemid>
<subitems>
<subitemid>1</subitemid>
<subitemid>2</subitemid>
</subitems>
<itemid>2</itemid>
<subitems>
<subitemid>7</subitemid>
<subitemid>10</subitemid>
</subitems>
<itemid>9</itemid>
<subitems>
<subitemid>12</subitemid>
<subitemid>16</subitemid>
</subitems>
</items>
</job>
</jobs>
As this XML is, you cannot properly parse it. You would need to change it - you should put each item with its itemid and subitems into a separate <item> node - otherwise you just have a long list of <itemid> and <subitems> nodes under your <items> main node, but you have no means of telling which <itemid> and <subitems> nodes belong together ....
You need to change your XML to be something like this:
<job>
<jobid>4711</jobid>
<items>
<item>
<itemid>1</itemid>
<subitems>
<subitemid>1</subitemid>
<subitemid>2</subitemid>
</subitems>
</item>
<item>
<itemid>2</itemid>
<subitems>
......
</subitems>
</item>
... (possibly more <item> nodes) ....
</items>
</job>
THEN you could use basically the same code I had for your previous question - extended to cover three levels:
CREATE PROCEDURE dbo.SaveJobs (#input XML)
AS BEGIN
;WITH JobsData AS
(
SELECT
JobID = JobNode.value('(jobid)[1]', 'int'),
ItemID = ItemNode.value('(itemid)[1]', 'int'),
SubItemID = SubItemNode.value('.', 'int')
FROM
#input.nodes('/jobs/job') AS TblJobs(JobNode)
CROSS APPLY
JobNode.nodes('items/item') AS TblItems(ItemNode)
CROSS APPLY
ItemNode.nodes('subitems/subitem') AS TblSubItems(SubItemNode)
)
INSERT INTO dbo.tblDummy(JobID, ItemID, SubItemID)
SELECT JobID, ItemID, SubItemID
FROM JobsData
END
Basically, you need three "lists" of XML nodes:
first you need the list of all <jobs>/<job> nodes to get the jobid values
for each of those job nodes, you will also need to get their list of nested <items>/<item> to get the itemid value
from each node, you then also get the list of <subitems>/<subitem>
This will most likely work - but most likely, it will be rather slow (three nested calls to the .nodes() function!).
Update:
OK, so the first call #input.nodes('/jobs/job') AS TblJobs(JobNode) basically creates a "pseudo" table TblJobs with a single column JobNode and each <job> element in your XML is being stored into a row in that pseudo table - so the first row will contain this XML in it's JobNode column:
<job>
<jobid>4711</jobid>
<items>
<item>
<itemid>1</itemid>
<subitems>
<subitemid>1</subitemid>
<subitemid>2</subitemid>
</subitems>
</item>
<item>
<itemid>2</itemid>
<subitems>
......
</subitems>
</item>
... (possibly more <item> nodes) ....
</items>
</job>
and each further row will contain the additional XML fragments for each subsequent <job> element inside <jobs>
From each of those XML fragments, the second call
CROSS APPLY JobNode.nodes('items/item') AS TblItems(ItemNode)
again selects a list of XML fragments into a pseudo table (TblItems) with a single column ItemNode that contains the XML fragment for each <item> node inside that <job> node we're dealing with currently.
So the first row in this pseudo-table contains:
<item>
<itemid>1</itemid>
<subitems>
<subitemid>1</subitemid>
<subitemid>2</subitemid>
</subitems>
</item>
and the second row will contain
<item>
<itemid>2</itemid>
<subitems>
......
</subitems>
</item>
and so on.
And then the third call - you've guessed it - again extracts a list of XML elements as rows into a pseudo-table - one entry for each <subitem> node in your XML fragment.
Update #2:
I'm new to "JobID = JobNode.value('(jobid)[1]', 'int')" line of code
OK - given the <Job> XML fragment that you have:
<job>
<jobid>4711</jobid>
<items>
......
</items>
</job>
the .value() call just executes this XPath expression (jobid) on that XML and basically gets back the <jobid>4711</jobid> snippet. It then extracts the value of that node (the inner text), and the second parameter of the .value() call defines what SQL data type to interpret this as - so it basically grabs the 4711 from the <jobid> node and interprets it as an int
You can take a composite key of Jobid and Itemid as primary key.

Accessing child nodes in SQLXML columns with XQuery

I have a database which has a table with an XML column. The XML data has a bunch of child nodes which look something like this:
<test>
<result id="1234">
<data elementname="Message">some error message</data>
<data elementname="Cat">Cat01</data>
<data elementname="Type">WARNING</data>
</result>
<result id="5678">
<data elementname="Message">some error message</data>
<data elementname="Cat">Cat01</data>
<data elementname="Type">WARNING</data>
</result>
</test>
The Cat element can have a number of different values. I'm trying to create reports on this data, so one thing I'd like to do is get a list of all the categories througout our data. This is my query:
Select Id, XmlData.query('/test/result/data[#elementname = ''Cat''] ') AS Message
From Table
WHERE XmlData.exist('/test/result/data[#elementname = ''Cat'']') = 1
ORDER BY FriendlyName
This correctly gets all the rows in my table with this type of categorization (there'll be other results in the same table without that element), but the categories are all combined into one column for each table record:
Id1, <data elementname="Cat">Cat01</data><data elementname="Cat">Cat01</data>
Id2, <data elementname="Cat">Cat01</data><data elementname="Cat">Cat01</data>
I'm including the Id column so it's easy to see where the data is coming from, the main problem is that I can only get it to concatenate the values for each row - I need each of those data elements to have its own row, then maybe do a Select Distinct on the result.
Is there a way I can do that?
Thanks
Always the Google after you post your question....
Think I found the answer here: http://blogs.msdn.com/b/simonince/archive/2009/04/24/flattening-xml-data-in-sql-server.aspx
SELECT DISTINCT cref.value('(text())[1]', 'varchar(50)') as Cat
FROM
SGIS CROSS APPLY
Data.nodes('/test/result') AS Results(rref) CROSS APPLY
rref.nodes('data[#elementname = ''Cat'']') AS Categories(cref)
Seems the key is the Cross Apply keywords

how to get unique elements?

<data>
<food>
<id>1</id>
<name>asparagus</name>
<catlog>7190</catlog>
</food>
<food>
<id>2</id>
<name>almonds</name>
<catlog>7190</catlog>
</food>
<food>
<id>3</id>
<name>asparagus</name>
<catlog>7192</catlog>
</food>
<food>
<id>4</id>
<name>asparagus</name>
<catlog>7193</catlog>
</food>
</data>
i would like to get the unique catlogs, so from this list i want to extract only 7190, 7192, and 7193. i have a script that puts it into a dropdownlist by using:
DropDownList1.DataSource = dv
DropDownList1.DataBind()
but i need it to get only the unique values.
Take a look at LINQ to XML! With this you have the power to directly query a blob of xml but with less headache than using XPATH (which you could also use to do the same task).
Then you could point your datasource at the result from the LINQ query over your XML blob.
Try the following
Public Function Unique(ByVal doc As XDocument) As IEnumerable(Of String)
Return doc...<catalog>.Select(Function(x) CType(x,Integer)).Distinct()
End Function
Quick Note: The CType may seem strange at first but it does work because the XElement class defines an explicit conversion operator for many value types including Integer.
LINQ is the prefered way I think, but an another option is :
Dim newTable As DataTable = dataView.ToTable( True, "Category")
DropDownList1.DataSource = newTable
DropDownList1.DataBind()

Resources