12

下面是我的 Postgres 表中的列响应。我想从我的 Postgres 数据库中的所有行中提取状态。状态也可能有不同的大小SUCCESS,所以我不想使用 substring 函数。有没有办法做到这一点?

<?xml version="1.0" ?><response><status>ERROR_MISSING_DATA</status><responseType>COUNTRY_MISSING</responseType><country_info>USA</country_info><phone_country_code>1234</phone_country_code></response>

所以我的表结构是这样的

   Column    |            Type             |                        Modifiers                         

-------------+-----------------------------+----------------------------------------------------------

 id          | bigint                      | not null default nextval('events_id_seq'::regclass)
 hostname    | text                        | not null
 time        | timestamp without time zone | not null
 trn_type    | text                        | 
 db_ret_code | text                        | 
 request     | text                        | 
 response    | text                        | 
 wait_time   | text                        | 

我想从每个请求中提取状态。我该怎么做呢?

下面是一个示例行。并假设表名 abc_events

id          | 1870667
hostname    | abcd.local
time        | 2013-04-16 00:00:23.861
trn_type    | A
request     | <?xml version="1.0" ?><response><status>ERROR_MISSING_DATA</status><responseType>COUNTRY_MISSING</responseType><country_info>USA</country_info><phone_country_code>1234</phone_country_code></response>
response    | <?xml version="1.0" ?><response><status>ERROR_MISSING_DATA</status><responseType>COUNTRY_MISSING</responseType><country_info>USA</country_info><phone_country_code>1234</phone_country_code></response>
4

1 回答 1

22

使用xpath()功能:

WITH x(col) AS (SELECT '<?xml version="1.0" ?><response><status>ERROR_MISSING_DATA</status></response>'::xml)
SELECT xpath('./status/text()', col) AS status
FROM   x

/text()剥离周围的<status>标签。在这种情况下,返回一个包含单个元素
的 - 数组:xml

status
xml[]
-------
{ERROR_MISSING_DATA}

应用于您的餐桌

针对您的问题更新,这可以简单地是:

SELECT id, xpath('./status/text()', response::xml) AS status
FROM   tbl;

如果您确定每行只有一个状态标记,您可以简单地从数组中提取第一项:

SELECT id, (xpath('./status/text()', response::xml))[1] AS status
FROM   tbl;

如果可以有多个状态项:

SELECT id, unnest(xpath('./status/text()', response::xml)) AS status
FROM   tbl;

每 1-n 行id

投射到xml

由于您将列定义为类型text(而不是xml,因此您需要显式转换xml。该函数xpath()需要类型的第二个参数xml。无类型的字符串常量被强制转换为xml自动,但text不是。您需要显式转换。

这无需显式强制转换即可工作:

  SELECT xpath('./status/text()'
      ,'<?xml version="1.0" ?><response><status>SUCCESS</status></response>')

像我的第一个示例中的CTE需要为“公用表表达式”中的每一列提供一个类型。如果我没有强制转换为特定类型,unknown则会使用该类型 - 这untyped string不同。unknown显然,和之间没有实现直接转换xml。您必须先转换为textunknown_type_col::text::xml. ::xml最好马上施放。

PostgreSQL 9.1(我认为)已经加强了这一点。旧版本更宽松。

无论哪种方式,使用这些方法中的任何一种,字符串都必须是有效的 xml,否则强制转换(隐式或显式)将引发异常。

于 2013-04-15T20:21:53.433 回答