How to concate joined table fields for xml - sql

Hi have data structure like this :
CREATE TEMP TABLE test_names (
id serial primary key,
name character varying(50),
age int
);
INSERT INTO test_names(name,age) values ('name1',10),('name2',20);
CREATE TEMP TABLE test_names_details (
id serial primary key,
test_names_id int,
col1 int,
col2 int,
col3 int
);
INSERT INTO test_names_details(test_names_id,col1,col2,col3)
VALUES(1,2,3,4),(1,5,6,7),(1,8,9,10),(2,20,21,22),(2,23,24,25)
Want from this tables select data like xml :
<info>
<maininfo>
<pn name="name">name1</pn>
<age name="age">10</age>
</maininfo>
<data>
<row>
<col1 name="col1">2</col1>
<col2 name="col2">3</col1>
<col3 name="col3">4</col1>
</row>
<row>
<col1 name="col1">5</col1>
<col2 name="col2">6</col1>
<col3 name="col3">7</col1>
</row>
<row>
<col1 name="col1">8</col1>
<col2 name="col2">9</col1>
<col3 name="col3">10</col1>
</row>
</data>
<maininfo>
<pn name="name">name2</pn>
<age name="age">20</age>
</maininfo>
<data>
<row>
<col1 name="col1">20</col1>
<col2 name="col2">21</col1>
<col3 name="col3">22</col1>
</row>
<row>
<col1 name="col1">23</col1>
<col2 name="col2">24</col1>
<col3 name="col3">25</col1>
</row>
</data>
</info>
How to do it ?

Wrap this in a function and off you go! ;-)
SELECT
'<info>' ||
string_agg(
'<maininfo>' ||
'<pn name="name">' || name || '</pn>' ||
'<age name="age">' || age || '</age>' ||
'</maininfo>' ||
'<data>' ||
(SELECT
string_agg(
'<row>' ||
'<col name="col1">'||col1||'</col>' ||
'<col name="col2">'||col2||'</col>' ||
'<col name="col3">'||col3||'</col>' ||
'</row>', '')
FROM test_names_details WHERE test_names_id = test_names.id
) ||
'</data>'
, '') ||
'</info>'
FROM test_names

Related

How to extract a nested array value frm XML in DataWeave and convert to CSV

I am getting this value from the database
<row>
<file_data>One</file_data>
<time_inserted>2019-01-30T10:29:20.543</time_inserted>
</row>
<row>
<file_data>two</file_data>
<time_inserted>2019-01-30T10:29:20.547</time_inserted>
</row>
<row>
<file_data>three</file_data>
<time_inserted>2019-01-30T10:29:20.550</time_inserted>
</row>
<row>
<file_data>four</file_data>
<time_inserted>2019-01-30T10:29:20.550</time_inserted>
</row>
<row>
<file_data>five</file_data>
<time_inserted>2019-01-30T10:29:20.553</time_inserted>
</row>
And I would like to output it as a CSV like this
one
two
three
four
five
I managed to solved my problem thusly:
Firstly I added a step in my logic to surround the data with a "rows" element so that it ended up looking like this:
<rows>
<row>
<file_data>One</file_data>
<time_inserted>2019-01-30T12:34:00.277</time_inserted>
</row>
<row>
<file_data>two</file_data>
<time_inserted>2019-01-30T12:34:00.277</time_inserted>
</row>
<row>
<file_data>three</file_data>
<time_inserted>2019-01-30T12:34:00.280</time_inserted>
</row>
<row>
<file_data>four</file_data>
<time_inserted>2019-01-30T12:34:00.280</time_inserted>
</row>
<row>
<file_data>five</file_data>
<time_inserted>2019-01-30T12:34:00.283</time_inserted>
</row>
</rows>
I then wrote this code to get the list output that I needed:
def responses = new XmlSlurper().parseText(xmlData)
def payload = ""
responses.row.findAll { p ->
p.file_data
}
.each { p ->
payload = payload + "${p.file_data}" + "\r\n"
}
print payload
And this outputs:
one
two
three
four
five
Hope below logic is works. please check it.
%dw 2.0
output application/java
---
payload.rows.*row map ($.file_data) reduce (($$ ++ "\n" ++ $))

XPath concat with EXTRACT function Oracle

I want to extract the values of "KEY" and "VALUE" and concat these results using XPath with EXTRACT.
Sample XML as below.
<PivotSet>
<item>
<column name = "KEY">RET_1</column>
<column name = "VALUE">A</column>
</item>
<item>
<column name = "KEY">RET_2</column>
<column name = "VALUE">R</column>
</item>
<item>
<column name = "KEY">RET_3</column>
<column name = "VALUE">P</column>
</item>
</PivotSet>
I need to return in SQL something like
RET_1#A;RET_2#R;RET_3#P
where the delimiter '#' separates the key/value and ':' separates the items. I want to do it with EXTRACT and XPath.
You can use ListAgg along with an XmlTable, see below:
select LISTAGG(keyItem || '#' || keyValue, ';') WITHIN GROUP (ORDER BY keyItem) AS Concated
from XmlTable( '/PivotSet/item' PASSING XmlType('<PivotSet>
<item>
<column name = "KEY">RET_1</column>
<column name = "VALUE">A</column>
</item>
<item>
<column name = "KEY">RET_2</column>
<column name = "VALUE">R</column>
</item>
<item>
<column name = "KEY">RET_3</column>
<column name = "VALUE">P</column>
</item>
</PivotSet>') COLUMNS keyItem PATH '*:column[#name = "KEY"]',
keyValue PATH '*:column[#name = "VALUE"]');
You could use ExtractValue, but you would need to know how many //item elements are in your XML and then indicate in your path portion of the extract call, but this is a little messy IMO:
SELECT ExtractValue(xmlOut, '//item[1]/column[#name="KEY"]') || '#' || ExtractValue(xmlOut, '//item[1]/column[#name="VALUE"]') || ';' ||
ExtractValue(xmlOut, '//item[2]/column[#name="KEY"]') || '#' || ExtractValue(xmlOut, '//item[2]/column[#name="VALUE"]') || ';' ||
ExtractValue(xmlOut, '//item[3]/column[#name="KEY"]') || '#' || ExtractValue(xmlOut, '//item[3]/column[#name="VALUE"]') As Concatted
FROM
(
SELECT XmlType('<PivotSet>
<item>
<column name = "KEY">RET_1</column>
<column name = "VALUE">A</column>
</item>
<item>
<column name = "KEY">RET_2</column>
<column name = "VALUE">R</column>
</item>
<item>
<column name = "KEY">RET_3</column>
<column name = "VALUE">P</column>
</item>
</PivotSet>') as xmlOut FROM dual
);

Extracting xmlsequence from another xmlsequance in SQL

I have small problem with xmlsequence. I am codding in PL-SQL (Oracle)
Let's say, my XML looks like this:
<Row name="Row1">
<Field name="Filed1">
<Value1>
</Value1>
</Field>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
<Row name="Row1">
<Field name="Filed1">
<Value1>
</Value1>
</Field>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
<Row name="Row2inRow1">
<Field name="Filed2">
<Value1>
</Value1>
</Field>
</Row>
It has 2x same "Row1" which is multiplicated, what's more inside Row1 I have multiplicated "Row2inRow1".
The problem is, I would like to select values from Ro2InRow1 and from Row1, to concat them, the effect should be:
Value1 (from 1st Row1) || Value1 (from 1st Row2inRow1)
Value1(from 1st Row1) || Value1 (from 2nd Row2InRow1)
Value1 (from 2nd Row1) || Value1 (from 3rd Row2inRow1)
Value1(from 2nd Row1) || Value1 (from 4th Row2InRow1)
I've tried to code is somehow, but I can't force my query to work right:
declare
xml_data xmldata;
begin
for rec1 in(select extractvalue(value(x),'//Field[#name="Filed1"]/Value1') ValueOfField1,
from table(xmlsequence(extract(xml_data.data,'//Row[#name="Row1"]')))x )
loop
dbms_output.put_line('1 : '|| ValueOfField1);
for rec2 in(select extractvalue(value(x),'//Field[#name="Filed2"]/Value1') ValueOfField2,
from table(xmlsequence(extract(xml_data.data,'//Row[#name="Row2inRow1"]')))k ) --? What here!
loop
dbms_output.put_line('1 : '|| ValueOfField2);
end loop;
end loop;
end;
Any ideas ? :(

How to do multiple loops through XML in PL/SQL

My XML looks like this
<data>
<row>
<id>1</id>
<name>John</name>
<name>Jack</name>
</row>
<row>
<id>2</id>
<name>Scott</name>
<name>Chuck</name>
<name>Kim</name>
</row>
</data>
I would like output:
->1
-->John
-->Jack
->2
-->Scott
-->Chuck
-->Kim
My current code looks like this:
DECLARE
X XMLTYPE := XMLTYPE('<?xml version="1.0" ?>
<data>
<row>
<id>1</id>
<name>John</name>
<name>Jack</name>
</row>
<row>
<id>2</id>
<name>Scott</name>
<name>Chuck</name>
<name>Kim</name>
</row>
</data>');
BEGIN
FOR R IN (SELECT EXTRACTVALUE(VALUE(P), '/row/id/text()') AS NAME
FROM TABLE(XMLSEQUENCE(EXTRACT(X, '//data/row'))) P)
LOOP
DBMS_OUTPUT.PUT_LINE('-->' || R.NAME);
END LOOP;
END;
I would need one more loop inside a row to loop through name tag, but I don't know how to do it.
A little help would be appreciated.
I figured it by myself:
DECLARE
X XMLTYPE := XMLTYPE('<?xml version="1.0" ?>
<data>
<row>
<id>1</id>
<promet>
<name>John</name>
<name>Jack</name>
</promet>
</row>
<row>
<id>2</id>
<promet>
<name>Scott</name>
<name>Chuck</name>
<name>Kim</name>
</promet>
</row>
</data>');
BEGIN
FOR R IN (SELECT EXTRACTVALUE(VALUE(P), '/row/id/text()') AS ID,
EXTRACT(VALUE(P), '/row/promet') AS PROMET
FROM TABLE(XMLSEQUENCE(EXTRACT(X, '//data/row'))) P)
LOOP
DBMS_OUTPUT.PUT_LINE('-->' || R.ID);
FOR R1 IN (SELECT EXTRACTVALUE(VALUE(T1), '/name/text()') AS NAME
FROM TABLE(XMLSEQUENCE(EXTRACT(R.PROMET, 'promet/name'))) T1)
LOOP
DBMS_OUTPUT.PUT_LINE('-->' || R1.NAME);
END LOOP;
END LOOP;
END;

bulk insert and parse a complex XML file into several tables

I have the following sql stored procedure to bulk insert and parse an xml file and insert its data into several tables in a database.
The sql below works, however its inserting duplicate records into the #questions table and the #cards table.
Any help on this would be much appreciated. Thanks in advance.
Here is the XML file:
<?xml version="1.0" encoding="UTF-8"?>
<Users>
<User>
<UserInfo>
<Id>0001</Id>
<FirstName>John</FirstName>
<LastName>Doe</LastName>
<Email>Doejk#net.com</Email>
</UserInfo>
<Questions>
<Question>
<Id>1</Id>
<AnswerId>1</AnswerId>
</Question>
<Question>
<Id>2</Id>
<AnswerId>3</AnswerId>
</Question>
</Questions>
<Cards>
<Card>
<Id>1234</Id>
<Type>Digital</Type>
<Status>Active</Status>
</Card>
<Card>
<Id>1334</Id>
<Type>Physical</Type>
<Status>Not Active</Status>
</Card>
</Cards>
</User>
<User>
<UserInfo>
<Id>0002</Id>
<FirstName>Mary</FirstName>
<LastName>Doe</LastName>
<Email>Doem#net.com</Email>
</UserInfo>
<Questions>
<Question>
<Id>3</Id>
<AnswerId>6</AnswerId>
</Question>
<Question>
<Id>4</Id>
<AnswerId>7</AnswerId>
</Question>
</Questions>
<Cards>
<Card>
<Id>3333</Id>
<Type>Digital</Type>
<Status>Active</Status>
</Card>
<Card>
<Id>4444</Id>
<Type>Physical</Type>
<Status>Active</Status>
</Card>
</Cards>
</User>
</Users>
Here is SQL code
/*************************************************************************
-- CREATE TEMP TABLES --
**************************************************************************/
CREATE TABLE #XMLDATA
(RecordId int IDENTITY(1,1) NOT NULL,
XmlData xml NOT NULL)
CREATE TABLE #USERS
(UserID int null,
firstname varchar(50) null,
lastname varchar(50) null,
email varchar(50) null)
CREATE TABLE #CARDS
(CardId int null,
userid int null,
card_type varchar(50) null,
card_status varchar(50) null)
CREATE TABLE #QUESTIONS
(UserID int null,
Question_ID int null,
Answer_ID int null)
/*************************************************************************
-- LOAD THE WHOLE XML AS SINGLE BLOB --
**************************************************************************/
INSERT INTO #XMLDATA(XmlData)
SELECT *
FROM OPENROWSET(
BULK 'c:\users.xml', SINGLE_BLOB)
/*************************************************************************
-- INSERT USERS --
**************************************************************************/
INSERT INTO #USERS
(userid, firstname, lastname, email)
SELECT href.value('(Id/text())[1]', 'integer'),
href.value('(FirstName/text())[1]', 'varchar(50)'),
href.value('(LastName/text())[1]', 'varchar(50)'),
href.value('(Email/text())[1]', 'varchar(30)'),
FROM #XMLDATA CROSS APPLY
XmlData.nodes('Users') AS userinfo(href)
/*************************************************************************
-- INSERT QUESTIONS INFORMATION --
**************************************************************************/
INSERT INTO #QUESTIONS
(UserId, Question_ID, Answer_ID)
SELECT sref.value('(Id/text())[1]', 'integer'),
qref.value('(Id/text())[1]', 'integer'),
qref.value('(AnswerId/text())[1]', 'integer')
FROM #XMLDATA CROSS APPLY
XmlData.nodes('Users/Questions/Question') AS Ques(qref) CROSS APPLY
XmlData.nodes('Users') AS userinf(sref)
/*************************************************************************
-- INSERT CARD INFORMATION --
**************************************************************************/
INSERT INTO #CARDS
(userid, card_id, card_type,card_status)
SELECT sref.value('(Id/text())[1]', 'integer'),
cref.value('(Id/text())[1]', 'integer'),
cref.value('(Type/text())[1]', 'varchar(50)'),
cref.value('(Status/text())[1]', 'varchar(50)')
FROM #XMLDATA CROSS APPLY
XmlData.nodes('/Users/Cards/Card') AS cardlist(cref) CROSS APPLY
XmlData.nodes('/Users') AS userinf(sref)
I'm not sure what your CROSS JOIN is about.
Here is some shredding.
Tip: Comment out the INSERT portion and just do the SELECT portion until you get those tweaked correctly.
DECLARE #data XML;
SET #data =
N'
<Users>
<User>
<UserInfo>
<Id>0001</Id>
<FirstName>John</FirstName>
<LastName>Doe</LastName>
<Email>Doejk#net.com</Email>
</UserInfo>
<Questions>
<Question>
<Id>1</Id>
<AnswerId>1</AnswerId>
</Question>
<Question>
<Id>2</Id>
<AnswerId>3</AnswerId>
</Question>
</Questions>
<Cards>
<Card>
<Id>1234</Id>
<Type>Digital</Type>
<Status>Active</Status>
</Card>
<Card>
<Id>1334</Id>
<Type>Physical</Type>
<Status>Not Active</Status>
</Card>
</Cards>
</User>
<User>
<UserInfo>
<Id>0002</Id>
<FirstName>Mary</FirstName>
<LastName>Doe</LastName>
<Email>Doem#net.com</Email>
</UserInfo>
<Questions>
<Question>
<Id>3</Id>
<AnswerId>6</AnswerId>
</Question>
<Question>
<Id>4</Id>
<AnswerId>7</AnswerId>
</Question>
</Questions>
<Cards>
<Card>
<Id>3333</Id>
<Type>Digital</Type>
<Status>Active</Status>
</Card>
<Card>
<Id>4444</Id>
<Type>Physical</Type>
<Status>Active</Status>
</Card>
</Cards>
</User>
</Users>';
SELECT T.myEntity.value('(Id)[1]', 'VARCHAR(20)')
, T.myEntity.value('(FirstName)[1]', 'VARCHAR(20)')
, T.myEntity.value('(LastName)[1]', 'VARCHAR(20)')
, T.myEntity.value('(Email)[1]', 'VARCHAR(20)')
FROM #data.nodes('Users/User/UserInfo') AS T(myEntity);
SELECT
T.myEntity.value('(../../UserInfo/Id)[1]', 'VARCHAR(20)')
, T.myEntity.value('(Id)[1]', 'INT')
, T.myEntity.value('(AnswerId)[1]', 'INT')
FROM #data.nodes('Users/User/Questions/Question') AS T(myEntity);
SELECT
T.myEntity.value('(../../UserInfo/Id)[1]', 'VARCHAR(20)')
, T.myEntity.value('(Id)[1]', 'INT')
, T.myEntity.value('(Type)[1]', 'VARCHAR(20)')
, T.myEntity.value('(Status)[1]', 'VARCHAR(20)')
FROM #data.nodes('Users/User/Cards/Card') AS T(myEntity);
CREATE TABLE #XMLDATA
(RecordId int IDENTITY(1,1) NOT NULL,
XmlData xml NOT NULL)
CREATE TABLE #USERS
(UserID int null,
firstname varchar(50) null,
lastname varchar(50) null,
email varchar(50) null)