我在postgreSQL中有一个表 history(id int,content xml)。其中一个id的XML内容如下
<history-data>
<history recorded-date="20110601">
<assignees>
<assignee>
<last-name>CIENA LUXEMBOURG</last-name>
</assignee>
</assignees>
<assignors>
<assignor execution-date="20110517">
<last-name>NORTEL NETWORKS LIMITED</last-name>
</assignor>
</assignors>
</history>
<history recorded-date="20110601">
<assignees>
<assignee>
<last-name>CIENA CORPORATION</last-name>
</assignee>
</assignees>
<assignors>
<assignor execution-date="20110527">
<last-name>CIENA LUXEMBOURG</last-name>
</assignor>
</assignors>
</history>
<history recorded-date="20090430">
<assignees>
<assignee>
<last-name>NORTEL NETWORKS</last-name>
</assignee>
</assignees>
<assignors>
<assignor execution-date="20090424">
<last-name>MAK, GARY</last-name>
</assignor>
<assignor execution-date="20090424">
<last-name>VELEZ, EDGAR</last-name>
</assignor>
</assignors>
</history>
</history-data>
在这里,我希望获得姓氏&amp;它的相应执行日期。对于上面的例子,我想要以下输出
last-name execution-date
================ ==============
CIENA LUXEMBOURG 20110517
CIENA CORPORATION 20110527
NORTEL NETWORKS 20090424
我能够使用以下SQL查询生成所有可能的组合,但无法获得如上所述的输出
SELECT id, unnest(CAST(xpath('/history-data/history/assignees/assignee/last-name/text()',content) AS text)::text[]) AS last-name,
unnest(CAST(xpath('/history-data/history/assignors/assignor/@execution-date',content) AS text)::text[]) AS execution-date
FROM history
WHERE id = 10
有关如何做到这一点的任何建议?
答案 0 :(得分:3)
您需要遍历所有history
个节点,并使用xpath()
函数获取相应的元素。默认情况下,xpath提取的结果返回 xml 的 array ,这就是我们需要使用数组索引(...)[1]
获取实际值的原因;示例查询可能如下:
SELECT
(xpath('//assignee/last-name/text()',xml_element))[1] AS "last-name",
(xpath('//assignor/@execution-date',xml_element))[1] AS "execution-date"
FROM (
SELECT unnest(xpath('//history',content)) AS xml_element FROM history
WHERE id = 10
) t;
结果是:
last-name | execution-date
-------------------+----------------
CIENA LUXEMBOURG | 20110517
CIENA CORPORATION | 20110527
NORTEL NETWORKS | 20090424
(3 rows)
当assignees
有多个assagnee
个节点时,查询应使用unnest()
来获取所有数组元素:
SELECT
unnest(xpath('//assignee/last-name/text()',xml_element)) AS "last-name",
unnest(xpath('//assignor/@execution-date',xml_element)) AS "execution-date"
FROM (
SELECT unnest(xpath('//history',content)) AS xml_element FROM history
WHERE id = 10
) t;
答案 1 :(得分:2)
您的要求是找到所有受让人,并且独立地找到所有执行日期,并返回笛卡尔积,这可能不是您真正想要的。
你想要的是:
history
元素history
元素找到您感兴趣的文字/属性。这意味着使用子查询:
SELECT
unnest(xpath('./assignees/assignee/last-name/text()',item))::text,
unnest(xpath('./assignors/assignor/@execution-date',item))::text
FROM (
SELECT
unnest(xpath('/history-data/history',content)) AS item
FROM history
WHERE id = 10
) s
GROUP BY 1,2;
请注意,如果您在单个assignee
元素中有多个history
,则可能会得到奇怪的结果。此外,不确定您是想要所有execution-date
,还是只需要第一个,最后一个,或者......
修改强>
要获取所有assignee
,但只列出第一个execution-date
:
SELECT
unnest(xpath('./assignees/assignee/last-name/text()',item))::text,
(xpath('./assignors/assignor/@execution-date',item))[1]::text
FROM (
SELECT
unnest(xpath('/history-data/history',content)) AS item
FROM history
WHERE id = 10
) s
GROUP BY 1,2;