FOR XML multiple control by attribute in tree concept - sql

I want to figure out one issue.
I already had question about simple ordering issue but I want to order more detail.
check below this link :
SQL Server : FOR XML sorting control by attribute
I made a example case.
SQL Query.
select (
select '123' AS '#id', (
select
(
select 'test' AS '#testid' , '20' AS '#order'
FOR XML path ('tree') , TYPE
),
(
select 'test2' AS '#testid' , '30' AS '#order'
FOR XML path ('tree-order') , TYPE
),
(
select 'test' AS '#testid' , '10' AS '#order'
FOR XML path ('tree') , TYPE
)
FOR XML path ('Node') , TYPE
)
FOR XML path ('Sample') , TYPE
),
(select '456' AS '#id', (
select
(
select 'test' AS '#testid' , '20' AS '#order'
FOR XML path ('tree') , TYPE
),
(
select 'test2' AS '#testid' , '30' AS '#order'
FOR XML path ('tree-order') , TYPE
),
(
select 'test' AS '#testid' , '10' AS '#order'
FOR XML path ('tree') , TYPE
)
FOR XML path ('Node') , TYPE
)
FOR XML path ('Sample') , TYPE)
FOR XML path ('Main') , TYPE
Result :
<Main>
<Sample id="123">
<Node>
<tree testid="test" order="20" />
<tree-order testid="test2" order="30" />
<tree testid="test" order="10" />
</Node>
</Sample>
<Sample id="456">
<Node>
<tree testid="test" order="20" />
<tree-order testid="test2" order="30" />
<tree testid="test" order="10" />
</Node>
</Sample>
</Main>
Expected result :
<Main>
<Sample id="123">
<Node>
<tree testid="test" order="10" />
<tree testid="test" order="20" />
<tree-order testid="test2" order="30" />
</Node>
</Sample>
<Sample id="456">
<Node>
<tree testid="test" order="10" />
<tree testid="test" order="20" />
<tree-order testid="test2" order="30" />
</Node>
</Sample>
</Main>
final result :
<Main>
<Sample id="123">
<Node>
<tree testid="test" />
<tree testid="test" />
<tree-order testid="test2" />
</Node>
</Sample>
<Sample id="456">
<Node>
<tree testid="test" />
<tree testid="test" />
<tree-order testid="test2" />
</Node>
</Sample>
</Main>
That's order by tree-order.
finally I don't want to show order information in attribute
Any one has great Idea?
Thank you for everybody who interesting to this.
Updated ----------------------------------------
Thank you every body finally I solved problem as below about order by and remove attribute issue :
declare #resultData xml = (select #data.query('
element Main {
for $s in Main/Sample
return element Sample {
$s/#*,
for $n in $s/Node
return element Node {
for $i in $n/*
order by $i/#order
return $i
}
}
}'));
SET #resultData.modify('delete (Main/Sample/Node/tree/#order)');
SET #resultData.modify('delete (Main/Sample/Node/tree-order/#order)');
select #resultData

select #data.query('
element Main {
for $s in Main/Sample
return element Sample {
$s/#*,
for $n in $s/Node
return element Node {
for $i in Node/*
order by $i/#order
return
if ($i/self::tree)
then element tree { $i/#testid }
else element tree-order { $i/#testid }
}
}
}
}')

What's interesting to me is that in your original post, you're stating that you're generating the XML as the result of a SQL query. If it were me, I'd control the ordering at that level.

Related

loop / Extract nodes from clob xml column in oracle pl sql

I have this xml content stored in a clob column of a table, I have to loop through the "molecule" nodes under the "reactantList" node,and store each "molecule" node into another table containing a list of molecules,
Any help please?
I tried with xmltype, xmlsequence, xmltable etc but did not work, I also have to specify the namespace "xmlns=.." somewhere as an argument to xmltype I think, to be able to make it work...
<cml xmlns="http://www.chemaxon.com" version="ChemAxon file format v20.20.0, generated by vunknown" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.chemaxon.com http://www.chemaxon.com/marvin/schema/mrvSchema_20_20_0.xsd">
<MDocument>
<MChemicalStruct>
<reaction>
<arrow type="DEFAULT" x1="-8.022119140625" y1="0.8333333333333334" x2="-3.5637858072916657" y2="0.8333333333333334" />
<reactantList>
<molecule molID="m1">
<atomArray>
<atom id="a1" elementType="C" x2="-13.938333333333334" y2="0.7083333333333333" />
<atom id="a2" elementType="O" x2="-15.478333333333333" y2="0.7083333333333333" lonePair="2" />
</atomArray>
<bondArray>
<bond id="b1" atomRefs2="a1 a2" order="1" />
</bondArray>
</molecule>
<molecule molID="m2">
<atomArray>
<atom id="a1" elementType="O" x2="-9.897119140624998" y2="0.8333333333333333" mrvValence="0" lonePair="3" />
</atomArray>
<bondArray />
</molecule>
</reactantList>
<agentList />
<productList />
</reaction>
</MChemicalStruct>
<MReactionSign toption="NOROT" fontScale="14.0" halign="CENTER" valign="CENTER" autoSize="true" id="o1">
<Field name="text">
<![CDATA[{D font=SansSerif,size=18,bold}+]]>
</Field>
<MPoint x="-11.730452473958332" y="0.6666666666666666" />
<MPoint x="-11.217119140624998" y="0.6666666666666666" />
<MPoint x="-11.217119140624998" y="1.18" />
<MPoint x="-11.730452473958332" y="1.18" />
</MReactionSign>
</MDocument>
</cml>
You can use:
INSERT INTO molecules (molecule)
SELECT x.molecule
FROM table_name t
CROSS APPLY XMLTABLE(
XMLNAMESPACES(
'http://www.w3.org/2001/XMLSchema-instance' AS "xsi",
DEFAULT 'http://www.chemaxon.com'
),
'/cml/MDocument/MChemicalStruct/reaction/reactantList/molecule'
PASSING XMLTYPE(t.xml)
COLUMNS
molecule XMLTYPE PATH '.'
) x
db<>fiddle here

How to get XML subnodes as strings along with parent attributes?

I need to parse xml which consist of nodes having attributes and subnodes. The result should be attribute of parent with xml of child node
declare #xml xml
set #xml = '<root>
<group Description="firstgroup">
<nodeA age="10" birthplace="Anchorage"/>
<nodeB mode="A" ability="read"/>
</group>
<group Description="nextgroup">
<nodeA age="10" birthplace="London"/>
<nodeB count="2" birthplace="Paris"/>
</group>
</root>'
select
c.value('#Description', 'varchar(max)') as 'Description'
from #xml.nodes('/root/*') as T(c)
The output is
Description
===========
firstgroup
nextgroup
But I need
Description nodeBXML
=========== ========
firstgroup <nodeB mode="A" ability="read"/>
nextgroup <nodeB count="2" birthplace="Paris"/>
select
c.value('#Description', 'varchar(max)') as 'Description'
, c.query('./nodeB') as Content
from #xml.nodes('/root/*') as T(c)
-- Results to:
Description Content
firstgroup <nodeB mode="A" ability="read" />
nextgroup <nodeB count="2" birthplace="Paris" />
Perhaps something like this:
Example
Select c.value('#Description', 'varchar(max)') as 'Description'
,AsString = convert(varchar(max),c.query('./*[2]') )
,AsXML = c.query('./*[2]')
From #xml.nodes('/root/*') as T(c)
Returns

FORXML SQL Group By Element

I am trying to group some elements together under one node. This is my current SQL;
declare #xml xml
set #xml = (
select (
select
'DERIVED' '#type',
m.NuixDerivedFieldName '#name', (
SELECT
NuixFieldType as 'metadata/#type',
NuixFieldName as 'metadata/#name'
from eddsdbo.MetadataMapping m1
where m1.NuixDerivedFieldName = m.NuixDerivedFieldName
for xml path ('first-non-blank'), type
)
from (select distinct NuixDerivedFieldName from eddsdbo.MetadataMapping) m
for xml path ('metadata'))
)
;WITH XMLNAMESPACES(DEFAULT 'http://nuix.com/fbi/metadata-profile')
select #xml for XML PATH ('metadata-list'), ROOT ('metadata-profile')
Which gives me the following output;
<metadata-profile xmlns="http://nuix.com/fbi/metadata-profile">
<metadata-list>
<metadata type="DERIVED" name="Barcode" xmlns="">
<first-non-blank>
<metadata type="CUSTOM" name="Barcode" />
</first-non-blank>
<first-non-blank>
<metadata type="EVIDENCE" name="Barcode" />
</first-non-blank>
</metadata>
I want to group together elements together which have the same 'name' attribute of the metadata element under the <first-non-blank> element.
The desired output should be;
<metadata-profile xmlns="http://nuix.com/fbi/metadata-profile">
<metadata-list>
<metadata type="DERIVED" name="Barcode" xmlns="">
<first-non-blank>
<metadata type="CUSTOM" name="Barcode" />
<metadata type="EVIDENCE" name="Barcode" />
</first-non-blank>
</metadata>
...
My database looks something like this;
NuixFieldName NuixFieldType NuixDerivedFieldName
------------------------------ ------------------------------ ------------------------------
_EmailEntryID PROPERTY EmailEntryID
Audited Audited Audited
Author PROPERTY Author
Barcode CUSTOM Barcode
Barcode EVIDENCE Barcode
I would also like to remove the xlmns namespace identifier from the metadata elements.
Thanks in advance!
You could try this
DECLARE #SampleData AS TABLE
(
NuixFieldName varchar(20),
NuixFieldType varchar(20),
NuixDerivedFieldName varchar(20)
)
INSERT INTO #SampleData
VALUES
('_EmailEntryID','PROPERTY','EmailEntryID'),
('Audited', 'Audited ','Audited'),
('Author ', 'PROPERTY','Author '),
('Barcode', 'CUSTOM ','Barcode'),
('Barcode', 'EVIDENCE','Barcode')
DECLARE #xml XML
SET #xml = (
SELECT
-- sd.NuixDerivedFieldName AS [#name],
'DERIVED' AS [#type],
sd.NuixDerivedFieldName AS [#name],
(
SELECT
sd2.NuixFieldType as '#type',
sd2.NuixFieldName as '#name'
FROM #SampleData sd2 WHERE sd2.NuixDerivedFieldName = sd.NuixDerivedFieldName
FOR XML PATH ('metadata'),ROOT('first-non-blank'), TYPE
)
FROM (select DISTINCT sd.NuixDerivedFieldName from #SampleData sd ) sd
FOR XML PATH('metadata'), ROOT('metadata-list'),TYPE
)
;WITH XMLNAMESPACES(DEFAULT 'http://nuix.com/fbi/metadata-profile')
SELECT #xml FOR XML PATH (''),ROOT('metadata-profile')
return:
<metadata-profile xmlns="http://nuix.com/fbi/metadata-profile">
<metadata-list>
<metadata type="DERIVED" name="Audited">
<first-non-blank>
<metadata type="Audited " name="Audited" />
</first-non-blank>
</metadata>
<metadata type="DERIVED" name="Author ">
<first-non-blank>
<metadata type="PROPERTY" name="Author " />
</first-non-blank>
</metadata>
<metadata type="DERIVED" name="Barcode">
<first-non-blank>
<metadata type="CUSTOM " name="Barcode" />
<metadata type="EVIDENCE" name="Barcode" />
</first-non-blank>
</metadata>
<metadata type="DERIVED" name="EmailEntryID">
<first-non-blank>
<metadata type="PROPERTY" name="_EmailEntryID" />
</first-non-blank>
</metadata>
</metadata-list>
</metadata-profile>

Using SQL to Generate XML

I'm trying to use SQL to generate XML in the format:
<ImportSession>
<Batches>
<Batch>
<BatchFields>
<BatchField Name="Field1" Value="1" />
<BatchField Name="Field2" Value="2" />
<BatchField Name="Field3" Value="3" />
</BatchFields>
<Batch>
<Batches>
</ImportSession>
I'm using SQL Server 2008. I wrote this query:
SELECT
(SELECT
(SELECT
'Col' AS [#Name],
FiscalYear AS [#Value]
FROM [ICEM].[dbo].[ExportedBill]
WHERE ExportedBillID = 1
FOR XML PATH ('BatchField'), TYPE)
FROM [ICEM].[dbo].[ExportedBill]
WHERE ExportedBillID = 1
FOR XML PATH ('BatchFields'), ROOT ('Batch'), TYPE)
FROM
[ICEM].[dbo].[ExportedBill]
WHERE
ExportedBillID = 1
FOR XML PATH ('Batches'), ROOT ('ImportSession')
And this results in:
<ImportSession>
<Batches>
<Batch>
<BatchFields>
<BatchField Name="Col" Value="2015" />
</BatchFields>
</Batch>
</Batches>
</ImportSession>
What I need though is every column should have an entry in BatchField. Also I need the column name to show up in the name. So I should get:
<BatchField Name="FiscalYear" Value="2015" />
<BatchField Name="MeterNumber" Value="123456" />
<BatchField Name="Name" Value="John Smith" />
<BatchField Name="Utility" Value="Electricity" />
So can anyone tell me how I modify my query to get what I need?
EDIT:
I figured it out. I needed a second nested Select. I need one for each column. If they proceeding selects use the same tags as a previous Select then the information is concatanated under the same parent tag
SELECT
(SELECT
(SELECT
'FiscalYear' AS [#Name],
FiscalYear AS [#Value]
FROM [ICEM].[dbo].[ExportedBill]
WHERE ExportedBillID = 1
FOR XML PATH ('BatchField'), TYPE),
(SELECT 'FiscalPeriod' AS [#Name],
FiscalPeriod AS [#Value]
FROM [PEEL_ICEM].[dbo].[ExportedBill]
WHERE ExportedBillID = 1
FOR XML PATH ('BatchField'), TYPE)
FROM [ICEM].[dbo].[ExportedBill]
WHERE ExportedBillID = 1
FOR XML PATH ('BatchFields'), ROOT ('Batch'), TYPE)
FROM
[ICEM].[dbo].[ExportedBill]
WHERE
ExportedBillID = 1
FOR XML PATH ('Batches'), ROOT ('ImportSession')
Thing is though, there will be around 70 columns in this table. Ill brute force it for now, but if anyone knows of a better way to do this please let me know. Cheers
You can create separate child elements by adding a blank column separator. e.g.
DECLARE #T TABLE
( FiscalYear INT,
MeterNumber INT,
Name VARCHAR(255),
Utility VARCHAR(255)
);
INSERT #T VALUES (2015, 123456, 'John Smith', 'Electricity');
SELECT [BatchField/#Name] = 'FiscalYear',
[BatchField/#Value] = FiscalYear,
'',
[BatchField/#Name] = 'MeterNumber',
[BatchField/#Value] = MeterNumber,
'',
[BatchField/#Name] = 'Name',
[BatchField/#Value] = Name,
'',
[BatchField/#Name] = 'Utility',
[BatchField/#Value] = Utility
FROM #T
FOR XML PATH('BatchFields'), ROOT('Batch');
Which gives:
<Batch>
<BatchFields>
<BatchField Name="FiscalYear" Value="2015" />
<BatchField Name="MeterNumber" Value="123456" />
<BatchField Name="Name" Value="John Smith" />
<BatchField Name="Utility" Value="Electricity" />
</BatchFields>
</Batch>

SQL xml query returns null

I have the following XML:
<Matter>
<CriticalDates>
<CriticalDate>
<CriticalDateId>2</CriticalDateId>
<Name>Instruction Date</Name>
<Value_FieldId>9F21</Value_FieldId>
<Confirmed_FieldId />
<Status>In Progress</Status>
<ConfirmStatus />
<CompPercent>0</CompPercent>
<Order>0</Order>
<Value>2014-03-28T06:00:00+11:00</Value>
<Confirmed>false</Confirmed>
</CriticalDate>
<CriticalDate>
<CriticalDateId>-2</CriticalDateId>
<Name>Completion Date</Name>
<Value_FieldId>9F22</Value_FieldId>
<Confirmed_FieldId>9F27</Confirmed_FieldId>
<Status>Complete</Status>
<ConfirmStatus />
<CompPercent>0</CompPercent>
<Order>1</Order>
<Value />
<Confirmed>false</Confirmed>
</CriticalDate>
<CriticalDate>
<CriticalDateId>-3</CriticalDateId>
<Name>Not Proceeding Date</Name>
<Value_FieldId>9F23</Value_FieldId>
<Confirmed_FieldId />
<Status>Not Proceeding</Status>
<ConfirmStatus />
<CompPercent>0</CompPercent>
<Order>2</Order>
<Value />
<Confirmed>false</Confirmed>
</CriticalDate>
</CriticalDates>
</Matter>
To select all the nodes as rows i'm using:
SELECT
MatterId,
MatterXml,
MD.CD.value('(Name)[1]', 'VARCHAR(50)') AS 'Name',
MD.CD.value('(Status)[1]', 'VARCHAR(50)') AS 'Status',
MD.CD.value('(value)[1]', 'DATE') AS 'CriticalDate',
MD.CD.value('(Confirmed)[1]', 'VARCHAR(50)') AS 'Confirmed'
FROM
dbo.Matter m
CROSS APPLY m.MatterXml.nodes('/Matter/CriticalDates/CriticalDate') AS MD(CD)
When i run this i get 3 rows back but all CriticalDates return as NULL even the first one when there is a date in the XML. Please help!
XML is case sensitive. Try is with:
MD.CD.value('(Value)[1]', 'DATE') AS 'CriticalDate',