Xml PostgreSQL Xpath来选择元素和它';将子属性设置为两列

Xml PostgreSQL Xpath来选择元素和它';将子属性设置为两列,xml,postgresql,xpath,Xml,Postgresql,Xpath,我在postgreSQL中有一个表历史记录(id int,content xml)。其中一个id的XML内容如下所示 <history-data> <history recorded-date="20110601"> <assignees> <assignee> <last-name>CIENA LUXEMBOURG</last-name>

我在postgreSQL中有一个表历史记录(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>
我能够使用下面的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

有什么建议可以这样做吗?

您的请求所做的是找到所有的受让人,并独立地找到所有的执行日期,然后返回笛卡尔积,这可能不是您真正想要的

你想要的是:

  • 查找所有
    历史记录
    元素
  • 然后,针对每个
    历史
    元素,找到您感兴趣的文本/属性
这意味着使用子查询:

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;
请注意,如果在一个
历史
元素中有多个
受让人
s,则可能会得到奇怪的结果。另外,不确定您是想要所有的
执行日期
s,还是只想要第一个、最后一个或

编辑

要获取所有
受让人
s,但仅列出第一个
执行日期

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;

您需要迭代所有
历史
节点,并使用函数获取适当的元素。默认情况下,xpath提取的结果返回xml数组,这就是为什么我们需要使用数组索引
(…)[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
具有多个
assagene
节点时,查询应使用
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;

非常感谢。这可以很好地工作,但当我有多个受让人&在单个历史记录中只有一个受让人时,它不会给出正确的结果。在这种情况下,我希望获得具有相同执行日期的两个受让人。你知道怎么做吗?当你有多个
assignee
@GainiRajeshwarThank的条目时,只需使用
unnest()
。是的,当有一个受让人时,这可以正常工作。即使在一个历史元素中有多个受让人,我也希望这样做有效。在这种情况下,我希望列出所有具有第一个执行日期(如果在单个历史记录中有多个转让人和执行日期)的受让人的第一个日期,或者按时间顺序列出第一个日期(如果有差异)?@jacron first datelisted@jacron谢谢你。但GroupBy在这里不能处理xml元素。您必须将其转换为文本或任何其他数据类型。相应地更新了答案。
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;