3

This query:

with x as (select
'<promotions>
    <promotion promotion-id="old-promotion">
        <enabled-flag>true</enabled-flag>
        <searchable-flag>false</searchable-flag>
    </promotion>
    <promotion promotion-id="new-promotion">
        <enabled-flag>false</enabled-flag>
        <searchable-flag>false</searchable-flag>
        <exclusivity>no</exclusivity>
        <price>100</price>
        <price>200</price>
        <price>300</price>
    </promotion>
</promotions>'::xml as t
)
select 
    xpath('/promotions/promotion/@promotion-id', t) promotion_id,
    xpath('/promotions/promotion/enabled-flag/text()', t) enabled_flag,
    xpath('/promotions/promotion/exclusivity/text()', t) exclusivity,
    xpath('/promotions/promotion/price/text()', t) price
from x

for which the elements exclusivity and price do not appear in the first promotion, but do appear in the second, yields this result:

"{old-promotion,new-promotion}";"{true,false}";"{no}";"{100,200,300}"

I need to figure out how I can get a result set which will allow me to line up the exclusivity and price data to their appropriate promotion_id's. Something like this

"{old-promotion,new-promotion}";"{true,false}";"{,no}";"{,"100,200,300"}"

What do I have to do to make that happen?

1 Answer 1

4

Consider this:

WITH x AS (SELECT
'<promotions>
    <promotion promotion-id="old-promotion">
        <enabled-flag>true</enabled-flag>
        <searchable-flag>false</searchable-flag>
    </promotion>
    <promotion promotion-id="new-promotion">
        <enabled-flag>false</enabled-flag>
        <searchable-flag>false</searchable-flag>
        <exclusivity>no</exclusivity>
        <price>100</price>
        <price>200</price>
        <price>300</price>
    </promotion>
</promotions>'::xml AS t
)
SELECT xpath('//@promotion-id',       node) promotion_id
      ,xpath('//enabled-flag/text()', node) enabled_flag
      ,xpath('//exclusivity/text()',  node) exclusivity
      ,xpath('//price/text()',        node) price
FROM (SELECT unnest(xpath('/promotions/promotion', t)) AS node FROM x) sub

The trick is to split the document into nodes first with the help of unnest().
Then extract attributes from each node. This way you get NULL values automatically for missing attributes.

Returns:

  promotion_id   | enabled_flag | exclusivity |     price
-----------------+--------------+-------------+---------------
 {old-promotion} | {true}       | {}          | {}
 {new-promotion} | {false}      | {no}        | {100,200,300}

Related question:
XPath query into hierarchical data, preserving ancestor–descendant relationship

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.