select * for xml path is omitting columns - sql

select * from ViewWhatever for xml path ('node') returns a well-formed xml document, but wherever there are NULL entries columns, the element for that column is missing.
How can I stop this from happening?
e.g.
Id | Date | Name
1 NULL Bill
2 2020-01-01 Bob
returns
<node>
<Id>1</Id>
<Name>Bill</Name>
</node>
<node>
<Id>2</Id>
<Date>2020-01-01...</Date>
<Name>Bob</Name>
</node>
But I want it to be:
<node>
<Id>1</Id>
<Date /> // This node should exist!
<Name>Bill</Name>
</node>
<node>
<Id>2</Id>
<Date>2020-01-01...</Date>
<Name>Bob</Name>
</node>

You need to use ELEMENTS XSINIL;
You can see how to do that here

Related

Extract Date Value from child node

I am needing to extract a date from a nested xml and am running into the issue of no output. The date I am attempting to retrieve is for Field name="A". My expected output is 2022-04-12. Here is the sample data along with the query I have generated. Not exactly sure where I am going wrong with the query. Any help will be greatly appreciated:
declare #xml xml
set #xml =
'<root xlmns="http://www.example.com">
<header></header>
<alt-header></alt-header>
<Main>
<Employee>
<Department>
<Category>
<Team>
<Name>Fun</Name>
<Sub>
<field name="A">
<Field-value xmlns:xsi="http://www.example2.com" xsi:type="date">
<value>2022-04-12</value>
</Field-value>
</field>
<field name="B">
<Field-value xmlns:xsi="http://www.example2.com" xsi:type="date">
<value>2021-04-12</value>
</Field-value>
</field>
</Sub>
</Team>
</Category>
</Department>
</Employee>
<Employee>
<Department>
<Category>
<Team>
<Name>Times</Name>
<Sub>
<field name="B">
<Field-value xmlns:xsi="http://www.cde.com" xsi:type="date">
<value>2021-04-12</value>
</Field-value>
</field>
</Sub>
</Team>
</Category>
</Department>
</Employee>
</Main>
</root>';
WITH XMLNAMESPACES (DEFAULT 'http://www.example.com',
'http://www.example2.com' as xsi)
SELECT x.query('./Department/Category/Team/Name[../Name="FUN"]/Sub/Field [#name="A"]/field-value/value').value('.', 'nvarchar(100)')A_date
from #xml.nodes('/root/Main/Employee') tempxml(x)
//Department/Category/Team[Name[text()="Fun"]]/Sub/field[#name="A"]/Field-value/value
The // in the beginning means that xpath will search everythere in the document. Since you are looking within Employee elements, you can change //Department to ./Department or even Department. All three should work.

XML generate from SQL Query with perfect XML structure

MY SQl "employee" Table Look Like
+-------+---------+--------+----------+
| Empid | Empname | Salary | Location |
+-------+---------+--------+----------+
| 1 | Arul | 100 | Chennai |
+-------+---------+--------+----------+
XML Generate from SQl Query:
select * from employee for xml path, root('root')
from this Sql Query I'm Getting My XML Files as given below
<root>
<employee>
<Empid>1</Empid>
<Empname>Arul</Empname>
<Salary>100</Salary>
<Location>Chennai</Location>
</employee>
</root>
But My Expected Output XML from SQL query as
<root>
<column>Empid</column>
<value>1</value>
<column>Empname</column>
<value>Arul</value>
</root>
As you were told already, the needed output format is really bad and erronous. Nevertheless this can be done quite easily:
DECLARE #mockup TABLE(Empid INT,Empname VARCHAR(100),Salary DECIMAL(10,4),[Location] VARCHAR(100));
INSERT INTO #mockup VALUES(1,'Arul',100,'Chennai')
,(2,'One',200,'More');
SELECT 'Empid' AS [Column]
,EmpId AS [Value]
,'Empname' AS [Column]
,Empname AS [Value]
-- follow this pattern...
FROM #mockup t
FOR XML PATH('employee'),ROOT('root');
The result
<root>
<employee>
<Column>Empid</Column>
<Value>1</Value>
<Column>Empname</Column>
<Value>Arul</Value>
</employee>
<employee>
<Column>Empid</Column>
<Value>2</Value>
<Column>Empname</Column>
<Value>One</Value>
</employee>
</root>
But - by any chance - you should try to change this format. This is awful to query and will be your private headache for sure...
Some better suggestions:
<Employee>
<Column name="EmpId" value="1" />
<Column name="Empname" value="Arul" />
</Employee>
or
<employee id="1" name="Arul" />
or
<employee>
<Id>1</Id>
<Name>Arul</Name>
</employee>
or (if you really, really want to stick with this), at least a column index like here
<root>
<employee>
<Column inx="1">Empid</Column>
<Value inx="1">1</Value>
<Column inx="2">Empname</Column>
<Value inx="2">Arul</Value>
</employee>
<employee>
<Column inx="1">Empid</Column>
<Value inx="1">2</Value>
<Column inx="2">Empname</Column>
<Value inx="2">One</Value>
</employee>
</root>
The query for the last one is this
SELECT 1 AS [Column/#inx]
,'Empid' AS [Column]
,1 AS [Value/#inx]
,EmpId AS [Value]
,2 AS [Column/#inx]
,'Empname' AS [Column]
,2 AS [Value/#inx]
,Empname AS [Value]
-- follow this pattern...
FROM #mockup t
FOR XML PATH('employee'),ROOT('root');

Extract values from XML String in oracle

How do you extract the value of an xml string in oracle e.g.
XML Example
<?xml version="1.0" encoding="UTF-8"?>
<node>
<key label="name">Test</key>
<key label="lastname">Test</key>
</node>
So far this is what I have tried to extract the values
SELECT <COLUMN>, EXTRACTVALUE(xmltype(<COLUMN>),'/node/lastname') AS TEST FROM <TABLE>;
But it always returns a null value.

Given the following XML in SQL Server, how do I get a value?

Here is my SQL. I cannot seem to get one single value out of this thing. It only works if I remove all of the xmlns attributes.
I think the problem is that this xml contains 2 default namespaces, one attached to the Response element and one attached to the Shipment element.
DECLARE #xml XML
SET #xml = '<TrackResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Response xmlns="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0">
<ResponseStatus>
<Code>1</Code>
<Description>Success</Description>
</ResponseStatus>
<TransactionReference />
</Response>
<Shipment xmlns="http://www.ups.com/XMLSchema/XOLTWS/Track/v2.0">
<InquiryNumber>
<Code>01</Code>
<Description>ShipmentIdentificationNumber</Description>
<Value>1ZA50209234098230</Value>
</InquiryNumber>
<ShipperNumber>A332098</ShipperNumber>
<ShipmentAddress>
<Type>
<Code>01</Code>
<Description>Shipper Address</Description>
</Type>
<Address>
<AddressLine>123 HWY X</AddressLine>
<City>SOMETOWN</City>
<StateProvinceCode>SW</StateProvinceCode>
<PostalCode>20291 1234</PostalCode>
<CountryCode>US</CountryCode>
</Address>
</ShipmentAddress>
<ShipmentWeight>
<UnitOfMeasurement>
<Code>LBS</Code>
</UnitOfMeasurement>
<Weight>0.00</Weight>
</ShipmentWeight>
<Service>
<Code>42</Code>
<Description>UPS GROUND</Description>
</Service>
<Package>
<TrackingNumber>1ZA50209234098230</TrackingNumber>
<PackageServiceOption>
<Type>
<Code>01</Code>
<Description>Signature Required</Description>
</Type>
</PackageServiceOption>
<Activity>
<ActivityLocation>
<Address>
<City>SOMEWHERE</City>
<StateProvinceCode>PA</StateProvinceCode>
<CountryCode>US</CountryCode>
</Address>
</ActivityLocation>
<Status>
<Type>X</Type>
<Description>Damage reported. / Damage claim under investigation.</Description>
<Code>UY</Code>
</Status>
<Date>20120424</Date>
<Time>125000</Time>
</Activity>
<Activity>
<ActivityLocation>
<Address>
<City>SOMEWHERE</City>
<StateProvinceCode>PA</StateProvinceCode>
<CountryCode>US</CountryCode>
</Address>
</ActivityLocation>
<Status>
<Type>X</Type>
<Description>All merchandise discarded. UPS will notify the sender with details of the damage.</Description>
<Code>GY</Code>
</Status>
<Date>20120423</Date>
<Time>115500</Time>
</Activity>
<PackageWeight>
<UnitOfMeasurement>
<Code>LBS</Code>
</UnitOfMeasurement>
<Weight>0.00</Weight>
</PackageWeight>
</Package>
</Shipment>
</TrackResponse>'
select Svc.Dsc.value('(/TrackResponse/Shipment/Service/Description)[1]', 'varchar(25)')
from #xml.nodes('/TrackResponse') as Svc(Dsc)
As #marc_s said, you are ignoring xml namespaces. Here is a sql fiddle example. This gives X, I think that is what you need. Read this article for more. Note : *:TrackResponse[1]/*: in the xpath
--Results: X
declare #xmlTable as table (
xmlData xml
)
insert into #xmlTable
select '<TrackResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Response xmlns="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0">
...
</TrackResponse>'
;with xmlnamespaces(default 'http://www.ups.com/XMLSchema/XOLTWS/Track/v2.0')
select
x.xmlData.value('(/*:TrackResponse[1]/*:Shipment[1]/Package[1]/Activity[1]/Status[1]/Type[1])','varchar(100)') as all_snacks
from #xmlTable x
Two problems:
you're blatantly ignoring the XML namespace that's defined on the <shipment> element
your XQuery expression was a bit off
Try this:
-- define XML namespace
;WITH XMLNAMESPACES('http://www.ups.com/XMLSchema/XOLTWS/Track/v2.0' AS ns)
select
Svc.Dsc.value('(ns:Shipment/ns:Service/ns:Description)[1]', 'varchar(25)')
from
-- this already selects all <TrackResponse> nodes - no need to repeat that in
-- your above call to .value()
#xml.nodes('/TrackResponse') as Svc(Dsc)
Gives me a result of:
UPS GROUND

Query to get XML output for hierarchical data using FOR XML PATH in SQL Server

I have a table with columns NodeId, NodeName, ParentNodeId and I want to ouput entire table data in the form of Xml like the following using SQL query. I think FOR XML PATH mode in Sql server can be used to achieve this (I use SQL Server 2008) using recursion, but not sure how. Thanks in advance
<?xml version="1.0" encoding="utf-8" ?>
<Nodes>
<Node Id="1" Name="node1">
<Node Id="11" Name="node11">
<Node Id="111" Name="node111" />
<Node Id="112" Name="node112" />
</Node>
</Node>
<Node Id="2" Name="node2">
<Node Id="21" Name="node21">
<Node Id="211" Name="node211" />
<Node Id="212" Name="node212" />
</Node>
</Node>
</Nodes>
I solved it using a stored procedure and a recursive function. code shown below. (actually I wanted this to generate a menu xml, so the code is shown for the menu.
CREATE PROCEDURE [dbo].[usp_GetMenu]
AS
BEGIN
SET NOCOUNT ON;
SELECT dbo.fnGetMenuItems(MenuId)
FROM dbo.Menu
WHERE ParentMenuId IS NULL
FOR XML PATH('MenuItems')
END
GO
CREATE FUNCTION [dbo].[fnGetMenuItems]
(
#MenuId int
)
RETURNS XML
WITH RETURNS NULL ON NULL INPUT
AS
BEGIN
RETURN
(
SELECT MenuId AS "#Id"
, [Name] AS "#Name"
, [URL] AS "#URL"
, [Key] AS "#Key"
, [dbo].[fnGetMenuItems](MenuId)
FROM dbo.Menu
WHERE ParentMenuId = #MenuId
FOR XML PATH('MenuItem'),TYPE
)
END
GO
This query will do it - however, it's not very clean in that you have to "manually" define the nesting and it won't just automatically scale to more levels deep....
SELECT
n.ID AS '#Id',
n.NAME AS '#Name',
(SELECT
n2.ID AS '#Id',
n2.NAME AS '#Name',
(SELECT
n3.ID AS '#Id',
n3.NAME AS '#Name'
FROM
dbo.Nodes n3
WHERE
n3.ParentNode = n2.ID
FOR XML PATH('Node'), TYPE
)
FROM
dbo.Nodes n2
WHERE
n2.ParentNode = n.ID
FOR XML PATH('Node'), TYPE
)
FROM
dbo.Nodes n
WHERE
n.ParentNode IS NULL
FOR XML PATH('Node'), ROOT('Nodes')
Output is:
<Nodes>
<Node Id="1" Name="node1">
<Node Id="11" Name="node11">
<Node Id="111" Name="node111" />
<Node Id="112" Name="node112" />
</Node>
</Node>
<Node Id="2" Name="node2">
<Node Id="21" Name="node21">
<Node Id="211" Name="node211" />
<Node Id="212" Name="node212" />
</Node>
</Node>
</Nodes>
I was hoping there would be a way to do this with a recursive CTE (Common Table Expression), but that didn't work out :-(