I have data like this:
ID DUE_DATE KIND UNPAID_AMOUNT REQUIRED_AMOUNT PAID_AMOUNT RECEIVED ENTERED
---------- ---------- ---------- ------------- --------------- ----------- ---------- ----------
9331779 2017-08-11 11 606.42 127.59 2017-07-17 2017-07-18
9331779 2017-08-11 11 606.42 446.81 2017-08-16 2017-08-17
9331779 2017-08-11 11 606.42 32.02 2017-09-15 2017-09-18
9331782 2017-11-11 11 606.42 95.57 2017-11-15 2017-11-16
9331782 2017-11-11 11 606.42 446.81 2017-12-15 2017-12-18
9331782 2017-11-11 11 606.42 64.04 2018-01-03 2018-01-04
I want to transform this into XML data, looking like:
<payment-list>
<payment>
<kind>11</kind>
<due>2017-08-11</due>
<amount>null/0</amount>
<waiting>606.42</waiting>
<related-payment-list>
<related-payment>
<received>2017-07-17</received>
<entered>2017-07-18</entered>
<amount>127.59</amount>
</related-payment>
<related-payment>
<received>2017-08-16</received>
<entered>2017-08-17</entered>
<amount>446.81</amount>
</related-payment>
<related-payment>...
</related-payment-list>
</payment>
<payment>
<kind>11</kind>
<due>2017-11-11</due>
<amount>null/0</amount>
<waiting>606.42</waiting>
<related-payment-list>
<related-payment>
<received>2017-11-15</received>
<entered>2017-11-16</entered>
<amount>95.57</amount>
</related-payment>
<related-payment>
<received>2017-12-15</received>
<entered>2017-12-18</entered>
<amount>446.81</amount>
</related-payment>
<related-payment>...
</related-payment-list>
</payment>
<payment-list>
Can this be done in single query? I have an idea/way to do it in loop, but maybe someone has other idea, using XMLAgg etc.
Nesting XMLAgg()
calls is a bit tricky, but you could do this in two stages; first get each ID/due/kind/amount with a list of related payments:
select id, due_date, kind, unpaid_amount, required_amount,
xmlagg(xmlelement("related-payment",
xmlforest(received as "received", entered as "entered", paid_amount as "amount")))
from your_table
group by id, due_date, kind, unpaid_amount, required_amount;
which with your sample data gives (with the XMl fragment serialized for readability):
ID DUE_DATE KIND UNPAID_AMOUNT REQUIRED_AMOUNT XMLSERIALIZE(CONTENTXMLAGG(XMLELEMENT("RELATED-PAYMENT",XMLFOREST(RECEIVEDAS"REC
---------- ---------- ---------- ------------- --------------- --------------------------------------------------------------------------------
9331779 2017-08-11 11 606.42 <related-payment>
<received>2017-07-17</received>
<entered>2017-07-18</entered>
<amount>127.59</amount>
</related-payment>
<related-payment>
<received>2017-09-15</received>
...
and then use that as an inline view for the second level of aggregation:
select
xmlelement("payment-list",
xmlagg(
xmlelement("payment",
xmlforest(kind as "kind",
to_char(due_date, 'YYYY-MM-DD') as "due",
nvl(unpaid_amount, 0) as "amount",
nvl(required_amount, 0) as "waiting",
related_payments as "related-payment-list"
)
)
)
) as result
from (
select id, due_date, kind, unpaid_amount, required_amount,
xmlagg(
xmlelement("related-payment",
xmlforest(received as "received",
entered as "entered",
paid_amount as "amount"
)
)
) as related_payments
from your_table
group by id, due_date, kind, unpaid_amount, required_amount
);
Demo with your sample data as a CTE, and again adding serialization for readability:
-- CTE for sample data
with your_table (id, due_date, kind, unpaid_amount, required_amount, paid_amount, received, entered) as (
select 9331779, date '2017-08-11', 11, null, 606.42, 127.59, date '2017-07-17', date '2017-07-18' from dual
union all select 9331779, date '2017-08-11', 11, null, 606.42, 446.81, date '2017-08-16', date '2017-08-17' from dual
union all select 9331779, date '2017-08-11', 11, null, 606.42, 32.02, date '2017-09-15', date '2017-09-18' from dual
union all select 9331782, date '2017-11-11', 11, null, 606.42, 95.57, date '2017-11-15', date '2017-11-16' from dual
union all select 9331782, date '2017-11-11', 11, null, 606.42, 446.81, date '2017-12-15', date '2017-12-18' from dual
union all select 9331782, date '2017-11-11', 11, null, 606.42, 64.04, date '2018-01-03', date '2018-01-04' from dual
)
-- actual query
select xmlserialize(document
xmlelement("payment-list",
xmlagg(
xmlelement("payment",
xmlforest(kind as "kind",
to_char(due_date, 'YYYY-MM-DD') as "due",
nvl(unpaid_amount, 0) as "amount",
nvl(required_amount, 0) as "waiting",
related_payments as "related-payment-list"
)
)
)
)
indent size=2) as result
from (
select id, due_date, kind, unpaid_amount, required_amount,
xmlagg(
xmlelement("related-payment",
xmlforest(received as "received",
entered as "entered",
paid_amount as "amount"
)
)
) as related_payments
from your_table
group by id, due_date, kind, unpaid_amount, required_amount
);
which gets:
RESULT
--------------------------------------------------------------------------------
<payment-list>
<payment>
<kind>11</kind>
<due>2017-08-11</due>
<amount>0</amount>
<waiting>606.42</waiting>
<related-payment-list>
<related-payment>
<received>2017-07-17</received>
<entered>2017-07-18</entered>
<amount>127.59</amount>
</related-payment>
<related-payment>
<received>2017-09-15</received>
<entered>2017-09-18</entered>
<amount>32.02</amount>
</related-payment>
<related-payment>
<received>2017-08-16</received>
<entered>2017-08-17</entered>
<amount>446.81</amount>
</related-payment>
</related-payment-list>
</payment>
<payment>
<kind>11</kind>
<due>2017-11-11</due>
<amount>0</amount>
<waiting>606.42</waiting>
<related-payment-list>
<related-payment>
<received>2017-11-15</received>
<entered>2017-11-16</entered>
<amount>95.57</amount>
</related-payment>
<related-payment>
<received>2018-01-03</received>
<entered>2018-01-04</entered>
<amount>64.04</amount>
</related-payment>
<related-payment>
<received>2017-12-15</received>
<entered>2017-12-18</entered>
<amount>446.81</amount>
</related-payment>
</related-payment-list>
</payment>
</payment-list>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.