I have several many to many relationships in my schema. For example, a package has many taskgroups, taskgroups in turn have many tasks. All tables are linked together via many to many tables, holding for instance the primary key of package and the primary key of taskgroup. (I know this is not strictly needed, since XML is one to many, but I couldn't think of a better structure).
Is it possible to get the query result as XML, reflecting the one-to-many structure? So, the result should be like this:
<package id=1>
<taskgroup id=1>
<task id=1>
<task id=2>
</taskgroup>
<taskgroup id=2>
<task id=3>
</taskgroup>
</package>
I have managed to get part of what I want by using the XMLELEMENT()
and XMLATTRIBUTE()
functions to get all the tasks. Like so:
SELECT XMLELEMENT(name task,
XMLATTRIBUTES(p.name as packageName),
XMLELEMENT(name description, t.description),
XMLELEMENT(name tutorial,
XMLELEMENT(name someTaskChild1, t.data1)),
XMLELEMENT(name objectives,
XMLELEMENT(name someTaskChild2, t.data2)),
)
FROM packages p
INNER JOIN package_taskgroup pt ON p.id = pt.package_id
INNER JOIN taskgroups tg on pt.taskgroup_id = tg.id
INNER JOIN taskgroup_task tt on tg.id = tt.taskgroup_id
INNER JOIN tasks t on tt.task_id = t.id
WHERE p.id = somePackageId AND tg.id = someTaskGroupId
The question is how to group these tasks into their parent table elements?
Try:
SELECT p.id as pack_id,
XMLELEMENT(name taskgroup,
XMLATTRIBUTES(tg.id as id),
XMLAGG(XMLELEMENT(name task,
XMLATTRIBUTES(t.id as id)) as xml_task_group
FROM packages p
JOIN package_taskgroup pt ON p.id = pt.package_id
JOIN taskgroups tg on pt.taskgroup_id = tg.id
JOIN taskgroup_task tt on tg.id = tt.taskgroup_id
JOIN tasks t on tt.task_id = t.id
WHERE p.id = somePackageId
GROUP BY p.id, tg.id
This will give you all the task groups for the p.id
you specified.
Then:
SELECT XMLELEMENT(name package,
XMLATTRIBUTES(pack_id as id),
XMLAGG(xml_task_group))
FROM (previous SELECT here)
This will give you the structure you specified.
Details: XMLAGG, XML functions
Joined select will look like this:
SELECT XMLELEMENT(name package,
XMLATTRIBUTES(pack_id as id),
XMLAGG(xml_task_group))
FROM (SELECT p.id as pack_id,
XMLELEMENT(name taskgroup,
XMLATTRIBUTES(tg.id as id),
XMLAGG(XMLELEMENT(name task,
XMLATTRIBUTES(t.id as id)
))) as xml_task_group
FROM packages p
JOIN package_taskgroup pt ON p.id = pt.package_id
JOIN taskgroups tg on pt.taskgroup_id = tg.id
JOIN taskgroup_task tt on tg.id = tt.taskgroup_id
JOIN tasks t on tt.task_id = t.id
WHERE p.id = somePackageId
GROUP BY p.id, tg.id) t
GROUP BY pack_id
I simply copied the first select into FROM
clause of the second.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With