How to generate XML using SQL PATH Mode, with Line Items - sql

I am trying to generate an XML string based on data in two SQL tables. One contains Order Header data, the other one Line Item data.
My problem is that I can't get the Line Item info to appear properly as multiple elements within a single order:
This is the SQL statement:
Select
LTRIM(RTRIM(H.CustPONbr)) As "Transactions/Transaction/CustomerOrdNumber",
(
Select LTRIM(RTRIM(InvtID)) As "data()" From X888_Amazon_Order_Line L1
Where L1.CpnyID = H.CpnyID And L1.CustPONbr = H.CustPONbr
FOR XML PATH (''), ELEMENTS
) As "Transactions/Transaction/LineItems/LineItem/InvtId"
From X888_Amazon_Order_Header H (nolock)
where h.CustPONbr = '99999014'
For XML PATH ('ProcessEngineSubmission'), Root ('XML'), ELEMENTS
This is the result that I get:
<XML>
<Transactions>
<Transaction>
<CustomerOrdNumber>99999014</CustomerOrdNumber>
<LineItems>
<LineItem>
<InvtId>TEST 1235 TEST 1234</InvtId>
</LineItem>
</LineItems>
</Transaction>
</Transactions>
</XML>
If I execute the inner select (replacing "data()" with InvtId), I get what I am trying to achieve:
<InvtId>TEST 1235</InvtId>
<InvtId>TEST 1234</InvtId>

Try it like this:
Nested selects need the ,TYPE extension to come back as XML...
You might need to specify a path in the inner PATH('') or give a name to the column with AS ...
Select LTRIM(RTRIM(H.CustPONbr)) As "Transactions/Transaction/CustomerOrdNumber"
,(
Select LTRIM(RTRIM(InvtID))
From X888_Amazon_Order_Line L1
Where L1.CpnyID = H.CpnyID And L1.CustPONbr = H.CustPONbr
FOR XML PATH (''), TYPE
) As "Transactions/Transaction/LineItems/LineItem/InvtId"
From X888_Amazon_Order_Header H (nolock)
where h.CustPONbr = '99999014'
For XML PATH ('ProcessEngineSubmission'), Root ('XML')

Related

SQL Server stored procedure - Table to XML

I created an XML Object from an SQL table but still need to insert a tag and hardcode a value for each of my columns.
Here is my query and result
SELECT
EmployeeName, RequestStatus
FROM K2.SmartBoxData.Akin_LeaveRequest_Header_SMO
WHERE ID =32
FOR XML PATH ('Message')
<Message>
<EmployeeName>Developer</EmployeeName>
<RequestStatus>Line Manager Approval</RequestStatus>
</Message>
Here is my desired result
<Message>
<tag>
<hardcode> my value </hardcode>
<EmployeeName>Developer</EmployeeName>
</tag>
<tag>
<hardcode> my value 2 </hardcode>
<RequestStatus>Line Manager Approval</RequestStatus>
</tag>
</Message>
You can use nested FOR XML subqueries to do this. Make sure to add ,TYPE to the nested FOR XML otherwise it will try escape it.
Do not specify column names for the subqueries
SELECT
(
SELECT
hardcode = ' my value ',
lrh.EmployeeName
FOR XML PATH('tag'), TYPE
),
(
SELECT
hardcode = ' my value 2 ',
lrh.RequestStatus
FOR XML PATH('tag'), TYPE
)
FROM SmartBoxData.Akin_LeaveRequest_Header_SMO lrh
WHERE ID =32
FOR XML PATH ('Message'), TYPE;
Alternatively specify column names, but an empty PATH
SELECT
tag = (
SELECT
hardcode = ' my value ',
lrh.EmployeeName
FOR XML PATH(''), TYPE
),
tag = (
SELECT
hardcode = ' my value 2 ',
lrh.RequestStatus
FOR XML PATH(''), TYPE
)
FROM SmartBoxData.Akin_LeaveRequest_Header_SMO lrh
WHERE ID =32
FOR XML PATH ('Message'), TYPE;
db<>fiddle

Wrapping an xml document loses utf coding

In Sql Server I'm using
select * from [Database].[dbo].[Table] for xml path ('whatever')
which gives me an xml output with, importantly, newline 
 notifiers on any entries that have the new lines.
I need this output wrapped in a few more xml formatting elements but using
select '<?xml version="1.0"?><root><whateverses>'
+ (select * from [Database].[dbo].[Table] for xml path ('whatever'))
+ '</whateverses></root>';
returns just a string, with the newlne notifiers MISSING.
How can I preserve these? How do I wrap my xml in a few extras while keeping the output as an xml?
By trying to wrap the XML in varchar/string you're implicitly converting the XML to varchar/string. If you want to embed the XML in other tags try something like the following:
select *
into [dbo].[Foo]
from (values ('Hello', 'World') ) Src ([Bar], [Baz]);
select *
from [dbo].[Foo]
for xml path ('whatever');
select (
select *
from [dbo].[Foo]
for xml path ('whatever'), type
)
for xml path('whateverses'), root('root');
Which yields the XML results:
<whatever>
<Bar>Hello</Bar>
<Baz>World</Baz>
</whatever>
and:
<root>
<whateverses>
<whatever>
<Bar>Hello</Bar>
<Baz>World</Baz>
</whatever>
</whateverses>
</root>

Convert Database To XML with Specific format

I have database with two tables: Transaction and from_person.
I need to convert it to specified format like this:
<transaction>
<transaction_number>TRNWEB0147</transaction_number
<transaction_location>felesteen</transaction_location>
<date_transaction>2016-05-25T00:00:00</date_transaction>
<from_funds_code>C</from_funds_code>
<from_person>
<gender>M</gender>
<title>Mr.</title>
<first_name>Mohamed</first_name>
<middle_name>Mohamed</middle_name>
<prefix>AHMED</prefix>
<last_name>yahia</last_name>
<birth_date>1984-11-16T00:00:00</birth_date>
<ssn>28411160225124</ssn>
</from_person>
</transaction>
I try to do this query:
select tr.transactionnumber
,tr.transaction_location
,tr.transaction_description
,tr.date_transaction
,tr.teller
,tr.authorized
,tr.transmode_
,tr.amount_local
,(select fp.from_funds_code
,fp.from_country
from from_person fp
where fp.from_funds_code = tr.t_from_my_client
for xml path(''), elements, type)
from dbo. [ transaction ] tr
for xml path(''), elements, type
but result become in this format:
<transaction_number>TRNWEB0147</transaction_number
<transaction_location>felesteen</transaction_location>
<date_transaction>2016-05-25T00:00:00</date_transaction>
<from_funds_code>C</from_funds_code>
<gender>M</gender>
<title>Mr.</title>
<first_name>Mohamed</first_name>
<middle_name>Mohamed</middle_name>
<prefix>AHMED</prefix>
<last_name>yahia</last_name>
<birth_date>1984-11-16T00:00:00</birth_date>
<ssn>28411160225124</ssn>
I tried many ways but not succeed, please help.
Please use this query.
SELECT transaction_number,transaction_location,date_transaction,from_funds_code,
(
SELECT gender,title,first_name,middle_name,prefix,last_name,birth_date,ssn
FROM from_person FP
WHERE FP.FROM_FUNDS_CODE =TR.T_FROM_MY_CLIENT
FOR XML PATH('from_person'), ELEMENTS, TYPE
)
FROM dbo.[TRANSACTION] TR
FOR XML PATH('transaction'), ELEMENTS, TYPE

Naming xml node based on value from DB column

Currently I have an xml structure that is built like this.
<Project>
<ProjectAttribute>
<AttributeId></AttributeId>
<FieldName></FieldName>
<Title></Title>
<DisplayRow></DisplayRow>
<DisplayColumn></DisplayColumn>
<IsRequired></IsRequired>
<RequiredErrorMessage></RequiredErrorMessage>
<DevExpressControl>
<DevExpressControlId></DevExpressControlId>
<Class></Class>
<ClientNamePrefix></ClientNamePrefix>
</DevExpressControl>
<DataType>
<DataTypeId></DataTypeId>
<Name></Name>
</DataType>
</ProjectAttribute>
</Project>
I want to rename ProjectAttribute with the value of FieldName. I am unsure how to do this at the moment, seeing how when I try to put the value of that field into the XML Path, I get an error.
Here is what my sql looks like.
Set #output = (
SELECT poa.AttributeId, pa.FieldName, pa.Title, poa.DisplayRow,
poa.DisplayColumn, poa.IsRequired, pa.RequiredErrorMessage,
(SELECT de.DevExpressControlId, de.Class, de.ClientNamePrefix
FROM SCC_DevExpressControl de
WHERE de.DevExpressControlId = pa.DevExpressControlId
FOR XML Path(''), type) AS DevExpressControl,
(SELECT dt.DataTypeId, dt.Name
FROM SCC_DataType dt
WHERE dt.DataTypeId = pa.DataTypeId
FOR XML Path(''), type) AS DataType
FROM SCC_ProjectOfficeAttribute poa
LEFT JOIN SCC_ProjectAttribute pa ON poa.AttributeId = pa.AttributeId
WHERE poa.OfficeId = #OfficeId
AND poa.Status = 1
ORDER BY poa.DisplayRow, poa.DisplayColumn
FOR XML Path('ProjectAttribute'), type, Root('Project'))
select #output
#OfficeId is just an int, and #output is simply the xml. Where I am writing in the XML Path for ProjectAttribute is what I want to replace. My question is how do I get that value in there?
UPDATE: I am still somewhat at a loss. I have tried moving things like AttributeId and FieldName into the main node itself for ProjectAttribute, but this does not really fulfill my requirements.

Change element name with xml.modify or other method in TSQL

Suppose you have a TSQL query:
1 as 'Category1/#Level',
2 as 'Category2/#Level',
t.MainCat as 'Category1',
t.SubCat as 'Category2'
FOR XML PATH (''), ROOT('Taxonomy')
which generates following result:
<Taxonomy>
<Category1 Level="1">Clothing</Category1>
<Category2 Level="2">Jeans</Category2>
</Taxonomy>
The element Category1 and Category2 have unique names for the sql query to generate and convert in to xml format. That's why I used Category1 and Category2. I would like the end result to be like this:
<Taxonomy>
<Category Level="1">Clothing</Category>
<Category Level="2">Jeans</Category>
</Taxonomy>
This could be done using XML EXPLICIT like here, but since my code is much larger it becomes very cluttered and complex quite fast.
With xml.modify you can change values or attributes, but not the element itself.
Is there a way to store the first query result in a #X1 xml variable and then change the element Category1 & Category2 into Category and put it into variable #X2? Something like a search and replace used in text files, but then during the query.
sneaking a null in between elements can do the trick:
Select
1 as 'Category/#Level',
t.MainCat as "Category",
null,
2 as 'Category/#Level',
t.SubCat as "Category"
FOR XML PATH (''), ROOT('Taxonomy')
Also you may use nesting:
select
(select 1 as '#Level', 'Clothing'
for xml path('Category'), type),
(select 2 as '#Level', 'Jeans'
for xml path('Category'), type)
for xml path('Taxonomy');
or values clause to construct list of categories before forming output xml:
select Cat.Level as '#Level', Cat.Value as 'text()'
from (values
(1, 'Clothing')
,(2, 'Jeans')
) Cat(Level, Value)
for xml path('Category'), root('Taxonomy');