如何使用PostgreSQL将一对多关系呈现给XML

ave*_*joe 6 xml postgresql select one-to-many

我的架构中有多个关系.例如,一个包有许多任务组,任务组又有许多任务.所有表都通过多个表链接在一起,例如包含主键和taskgroup的主键.(我知道这不是严格需要的,因为XML是一对多的,但我想不出更好的结构).

是否可以将查询结果作为XML来反映一对多结构?所以,结果应该是这样的:

<package id=1>
  <taskgroup id=1>
    <task id=1>
    <task id=2>
  </taskgroup>
  <taskgroup id=2>
    <task id=3>
  </taskgroup>
</package>
Run Code Online (Sandbox Code Playgroud)

通过使用XMLELEMENT()XMLATTRIBUTE()函数来获取所有任务,我已经设法获得了我想要的一部分.像这样:

    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
Run Code Online (Sandbox Code Playgroud)

问题是如何将这些任务分组到其父表元素中?

Igo*_*nko 6

尝试:

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
Run Code Online (Sandbox Code Playgroud)

这将为p.id您指定所有任务组.

然后:

SELECT XMLELEMENT(name package, 
                  XMLATTRIBUTES(pack_id as id),
                  XMLAGG(xml_task_group))
FROM (previous SELECT here)
Run Code Online (Sandbox Code Playgroud)

这将为您提供您指定的结构.

详细信息:XMLAGG,XML函数

加入选择将如下所示:

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
Run Code Online (Sandbox Code Playgroud)

我只是复制FROM了第二个的第一个select into 子句.

  • @averagejoe查看答案的更新. (2认同)