How to render one to many relationships to XML with PostgreSQL

烈酒焚心 提交于 2019-12-07 03:10:04

问题


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?


回答1:


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.




回答2:


You can try like this:

SELECT 
     T0."Mail",
     T0."UserName", 
     (SELECT xmlagg(xmlelement(name Screens, 
                               XMLELEMENT(name "IN1_ID","IN1."ID"),
                               XMLELEMENT(name "IN1_Name", IN1."Name")
                              )
                    ) 
             FROM "Advertisement"."Screen" IN1 
             WHERE T0."ID" = IN1."PlatformID"
    ) AS Screens 
    FROM "Sales"."Platform" T0

XNL Output will be like this:

<screens>
   <IN1_PlatformID>14</IN1_PlatformID>
   <IN1_Name>My Name</IN1_Name>
</screens>
<screens>
   <IN1_PlatformID>15</IN1_PlatformID>
   <IN1_Name>My Name 2</IN1_Name>
</screens>

at c# side you need to insert a root node to read this.

var doc = new System.Xml.XmlDocument();
doc.LoadXml("<rows>" + row["Screens"].ToString() + "</rows>");

After that, you can convert to dataset to read screens data easily:

var xmlReader = new System.Xml.XmlNodeReader(doc);
var dataSet = new System.Data.DataSet();
dataSet.ReadXml(xmlReader);
foreach (System.Data.DataRow item in dataSet.Tables[0].Rows){
    ...
}


来源:https://stackoverflow.com/questions/13988052/how-to-render-one-to-many-relationships-to-xml-with-postgresql

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!