I am trying to generate an XML file which looks like following.
<products>
<product>
<sku>12345</sku>
<attributes>
<attribute>
<name>AttributeName</name>
<row>
<name>ProdName</name>
<value>someProduct</value>
</row>
</attribute>
<attribute>
<name>AttributeName</name>
<row>
<name>color</name>
<value>Blue</value>
</row>
</attribute>
</attributes>
</product>
</products>
With following SQL query I could generate something very close but need to fine tune it.
bcp "SELECT RTRIM(LTRIM(sku)) as sku,
(SELECT 'AttributeName' AS [name],'ProdName' AS [row/name],ProdName AS [row/value] FOR XML PATH ('attribute'), Type),
(SELECT 'AttributeName' AS [name],'color' AS [row/name], color AS [row/value] FOR XML PATH ('attribute'), Type)
FROM Tbl_Product WHERE (SKU = 12345) FOR XML PATH ('product'), ROOT('products'),Type" queryout "..\Desktop\sample.xml" -c -T
<products>
<product>
<sku>12345</sku>
<!-- need <attributes> here -->
<attribute>
<name>AttributeName</name>
<row>
<name>ProdName</name>
<value>someProduct</value>
</row>
</attribute>
<attribute>
<name>AttributeName</name>
<row>
<name>color</name>
<value>Blue</value>
</row>
</attribute>
<!-- end <attributes> here-->
</product>
</products>
Is there a way to nest all <attribute> nodes inside <attributes>.
Thanks in advance!
I wasn't aware of String concatenation (+) in SQL. It took me over a week to figure that one little thing out. Here's what solved my problem. Might help someone else in future.
bcp "SELECT RTRIM(LTRIM(sku)) as sku, (SELECT 'AttributeName' AS [attribute/name],
'ProdName' AS [attribute/row/name],
ProdName AS [attribute/row/value],
+'',
'AttributeName' AS [attribute/name],
'color' AS [attribute/row/name],
color AS [attribute/row/value]
FROM Tbl_Product Where (SKU = TP.SKU)
FOR XML PATH (''), ROOT('attributes'), Type)
FROM Tbl_Product TP WHERE (SKU = 12345)
FOR XML PATH ('product'), ROOT('products'),Type" queryout "..\Desktop\sample.xml" -c -T
Related
I'm trying to create XML from SQL Server and I'm stuck with nested elements. I try different FOR XML parameters but still cannot get the correct results.
query looks like this:
SELECT
Product.ID, Product.ProductName,
(SELECT
Images.ProductImage AS image
FROM Images
WHERE Images.ProductID = Product.ID
FOR XML PATH ('image_list'), ELEMENTS, TYPE
)
FROM (SELECT DISTINCT ID, ProductName FROM Product) Product
FOR XML PATH ('products'), ELEMENTS, root ('Root')
and I want get this XML like this:
<Root>
<products>
<ID>1</ID>
<ProductName>product 1</ProductName>
<image_list>
<image>picture1.jpg</image>
<image>picture2.jpg</image>
<image>picture3.jpg</image>
</image_list>
</products>
<products>
<ID>2</ID>
<ProductName>product 2</ProductName>
<image_list>
<image>picture1.jpg</image>
<image>picture2.jpg</image>
</image_list>
</products>
</Root>
First part is OK, the image_list is a problem. Any advice?
I solved :) ..probably is good to post a qustion, after that brain starts to work :)
I add AS 'image_list' under subquery, remove ELEMENTS and PATH name.
And that's it.
SELECT
Product.ID, Product.ProductName,
(SELECT
Images.ProductImage AS image
FROM Images
WHERE Images.ProductID = Product.ID
FOR XML PATH (''), TYPE
) 'image_list'
FROM (SELECT DISTINCT ID, ProductName FROM Product) Product
FOR XML PATH ('products'), ELEMENTS, root ('Root')
Results is:
<Root>
<products>
<ID>1</ID>
<ProductName>product 1 </ProductName>
<image_list>
<image>picture1.jpg</image>
<image>picture2.jpg</image>
<image>picture3.jpg</image>
</image_list>
</products>
<products>
<ID>2</ID>
<ProductName>product 2 </ProductName>
<image_list>
<image>picture1.jpg</image>
<image>picture2.jpg</image>
</image_list>
</products>
</Root>
I have this below xml data which is stored in a table.
The XML Structure I have
<Response>
<Question ID="1">
<Value ID="1">I want a completely natural childbirth - no medical interventions for me</Value>
<Value ID="2">no medical interventions for me</Value>
</Question>
</Response>
I need to convert this XML to a slightly different format, like the below one.
The XML Structure I need
<Response>
<Question ID="1">
<SelectedChoices>
<Choice>
<ID>1</ID>
</Choice>
<Choice>
<ID>2</ID>
</Choice>
</SelectedChoices>
</Question>
</Response>
Here the "Value" is changed to "Choice" and "ID" attribute of "Value" element is changed to an element.
I know this can be done in other ways, like using an XSLT. But it will be much more helpful if can accomplish with SQL itself.
Can someone help me to convert this using SQL?
Use this variable to test the statements
DECLARE #xml XML=
N'<Response>
<Question ID="1">
<Value ID="1">I want a completely natural childbirth - no medical interventions for me</Value>
<Value ID="2">no medical interventions for me</Value>
</Question>
</Response>';
This can be done with FLWOR-XQuery:
The query will re-build the XML out of itself... Very similar to XSLT...
SELECT #xml.query(
N'
<Response>
{
for $q in /Response/Question
return
<Question ID="{$q/#ID}">
<SelectedChoices>
{
for $v in $q/Value
return <Choice><ID>{string($v/#ID)}</ID></Choice>
}
</SelectedChoices>
</Question>
}
</Response>
'
);
Another approach: Shredding and re-build
You'd reach the same with this, but I'd prefere the first...
WITH Shredded AS
(
SELECT q.value('#ID','int') AS qID
,v.value('#ID','int') AS vID
FROM #xml.nodes('/Response/Question') AS A(q)
OUTER APPLY q.nodes('Value') AS B(v)
)
SELECT t1.qID AS [#ID]
,(
SELECT t2.vID AS ID
FROM Shredded AS t2
WHERE t1.qID=t2.qID
FOR XML PATH('Choice'),ROOT('SelectedChoices'),TYPE
) AS [node()]
FROM Shredded AS t1
GROUP BY t1.qID
FOR XML PATH('Question'),ROOT('Response')
I follow this post[1] as a guide to build an example of query an array of UDT in WSO2 DSS. In the post just query an UDT, my config try to query an UDT array.
I created this in my DB, a dummy PROCEDURE to try this:
create or replace
TYPE "LIST_CUSTOMERS" IS TABLE OF customer_t
CREATE OR REPLACE
PROCEDURE getCustomer2(listcust OUT list_customers) IS
cust customer_t;
cust2 customer_t;
BEGIN
listcust := list_customers();
cust := customer_t(1, 'prabath');
cust2 := customer_t(2, 'jorge');
listcust.extend;
listcust(1) := cust;
listcust.extend;
listcust(2) := cust2;
END;
My DS is this:
<?xml version="1.0" encoding="UTF-8"?>
<data name="UDTSample2">
<config id="default">
<property name="org.wso2.ws.dataservice.driver">oracle.jdbc.driver.OracleDriver</property>
<property name="org.wso2.ws.dataservice.protocol">jdbc:oracle:thin:#localhost:1521:DBMB</property>
<property name="org.wso2.ws.dataservice.user">****</property>
<property name="org.wso2.ws.dataservice.password">****</property>
</config>
<query id="q3" useConfig="default">
<sql>call getCustomer2(?)</sql>
<result element="customers">
<element name="customer" arrayName="custArray" column="cust" optional="true"/>
</result>
<param name="cust" paramType="ARRAY" sqlType="ARRAY" type="OUT" structType="LIST_CUSTOMERS" />
</query>
<operation name="op3">
<call-query href="q3" />
</operation>
</data>
ant return:
<customers xmlns="http://ws.wso2.org/dataservice">
<customer>{1,prabath}</customer>
<customer>{2,jorge}</customer>
</customers>
but I want something like this:
<customers xmlns="http://ws.wso2.org/dataservice">
<customer>
<id>1</id>
<name>prabath<name>
</customer>
<customer>
<id>2</id>
<name>Jorge<name>
</customer>
</customers>
How can I accomplish this?
[1] http://prabathabey.blogspot.com/2012/05/query-udtsuser-defined-types-with-wso2.html
Not sure whether this kind of transformation can be done at DSS level because DSS gives back what it recieves from database. Better use WSO2 esb for this kind of transformation.
By the moment it's not possible to accomplish this scenario using just DSS. the DS response must be send to the WSO2 ESB to do the corresponding transformation before send the response to the client. A JIRA was created to do this in the future https://wso2.org/jira/browse/DS-1104
As a workaround, you can use a procedure returning a sys_refcursor.
It would look like this:
PROCEDURE getCustomer_CUR(cur_cust OUT SYS_REFCURSOR)
l_cust LIST_CUSTOMERS;
IS
-- Retrieve cust list:
getCustomer2(l_cust);
OPEN cur_cust for
select cast(multiset(select * from TABLE(l_cust)) as customer_t) from dual;
...
END;
Then you can do your DSS mapping something like:
<sql>call getCustomer_CUR(?)</sql>
<result element="customers">
<element arrayName="custArray" name="Customers">
<element column="custArray[0]" name="col0" xsdType=.../>
...
</element>
</result>
<param name="cust" sqlType="ORACLE_REF_CURSOR" type="OUT"/>
It is tedious but it works.
I would like to be able to write out an XML file in this specific format. I've been reading up on bcp and experimenting with FOR XML but can't seem to achieve what I need here. I would appreciate any help in the right direction. While I know I could refactor the code that would consume this XML output; I'd like to be adventurous here and stick to the task at hand without changing anything.
SQL code for recreating a temp var table dataset
declare #dataset table(Color nvarchar(10), Number int, Code nvarchar(10))
insert into #dataset
select 'Green', 12345, 'US1'
union
select 'Red', 56789, 'US2'
select * from #dataset
And from this query I would like to generate the following XML document.
<?xml version="1.0" encoding="utf-8" ?>
<test>
<collection>
<Case>
<input>
<attribute name="Color">Green</attribute>
<attribute name="Number">12345</attribute>
<attribute name="Code">US1</attribute>
</input>
</Case>
<Case>
<input>
<attribute name="Color">Red</attribute>
<attribute name="Number">56789</attribute>
<attribute name="Code">US2</attribute>
</input>
</Case>
</collection>
</test>
I will defer to you experts to tell me if this is too ridiculous to be accomplished, but I think it "is" possible as I've got a little close so far.
I've been tinkering with this and able to write out XML files.
exec master..xp_cmdshell 'bcp "Query Here" queryout "c:\filename.xml" -c -T'
Thanks SO members!
select (
select (
select 'Color' as [attribute/#name],
Color as [attribute],
null,
'Number' as [attribute/#name],
Number as [attribute],
null,
'Code' as [attribute/#name],
Code as [attribute]
for xml path('input'), type
)
from #dataset
for xml path('Case'), root('collection'), type
)
for xml path('test'), type
In one of my sql scripts, I need to execute a stored procedure with the following xml string
<Collection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Field>
<Attributes>
<Attribute Name="CODE1" IsRequired="true" Order="1" IsVisible="true"/>
<Attribute Name="CODE2" IsRequired="true" Order="2" IsVisible="true"/>
</Attributes>
<Rows>
<Row ProductState="5">
<Items>
<Item Name="PROD1" SendCustomer="false"/>
<Item Name="PROD2" SendCustomer="false"/>
</Items>
</Row>
</Rows>
</Field>
</Collection>
I get the Attribute and the Item information from different tables. I am writing a generic function in which you pass an ID and returns this XML string that is used by the SQL script to execute the stored procedure
Sometimes, I need to override the attribute values of some elements like SendCustomer. My initial thought was to deserialize this to a temp table, update the temp table with the override value and then serialize it back to XML.
So, essentially, the entire process boils down to:
Query tables, serialize to XML in the function
Deserialze XML, store in temp table
Override values if necessary
Serialze from table to XML again
Is there a more elegant way in sql server 2005 to do this entire process?
The XML datatype actually can be modified using XQuery. See the modify() method.
declare #x XML;
select #x = N'<Collection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Field>
<Attributes>
<Attribute Name="CODE1" IsRequired="true" Order="1" IsVisible="true"/>
<Attribute Name="CODE2" IsRequired="true" Order="2" IsVisible="true"/>
</Attributes>
<Rows>
<Row ProductState="5">
<Items>
<Item Name="PROD1" SendCustomer="false"/>
<Item Name="PROD2" SendCustomer="false"/>
</Items>
</Row>
</Rows>
</Field>
</Collection>';
set #x.modify(N'replace value of
(/Collection/Field/Rows/Row/Items/Item[#Name="PROD2"]/#SendCustomer)[1]
with "true"');
select #x;