带有嵌套数据的Postgresql XML到表

时间:2018-10-27 13:03:30

标签: xml postgresql

我有一些XML需要插入两个表中,即“产品”和“条形码”。 XML看起来像

<products>
  <product>
    <code>0001</code>
    <name>Prod1</name>
    <active>t</active>
    <barcodes>
        <barcode>0001666</barcode>
        <barcode>6660001</barcode>
    </barcodes>
  <product>
  <product>
    ... another one
  </product>

和产品表由三个属性组成,条形码表是一个简单的条形码,产品代码元组与产品表有关系。我可以做类似的事情

    insert into product (code, name, active) (
    with products(prod_row) as (select-xml-column-from-table)
        select 
            unnest(xpath('//product/code/text()', prod_row)),
            unnest(xpath('//product/name/text()', prod_row)),
            unnest(xpath('//product/active/text()', prod_row))
        from products
);

它适用于产品,但是有没有一种明智的方法可以在同一条语句中用对产品代码的引用来填充条形码表?

顺便说一句。我一直找不到能够将其插入布尔“ active”(是否有任何指针)的类型转换?

预先感谢,   尼克

2 个答案:

答案 0 :(得分:1)

demo: db<>fiddle

测试XML:

<products>
    <product>
        <code>0001</code>
        <name>Prod1</name>
        <active>t</active>
        <barcodes>
            <barcode>0001666</barcode>
            <barcode>6660001</barcode>
        </barcodes>
    </product>
    <product>
        <code>0002</code>
        <name>Prod2</name>
        <active>f</active>
        <barcodes>
            <barcode>0000420</barcode>
        </barcodes>
    </product>
</products>

查询:

WITH xmldata AS (
    SELECT '<products><product><code>0001</code><name>Prod1</name><active>t</active><barcodes><barcode>0001666</barcode><barcode>6660001</barcode></barcodes></product><product><code>0002</code><name>Prod2</name><active>f</active><barcodes><barcode>0000420</barcode></barcodes></product></products>'::xml
), insert_products AS (
    INSERT INTO products (code, name, active)
    SELECT 
        unnest(xpath('//product/code/text()', xml)),
        unnest(xpath('//product/name/text()', xml)),
        unnest(xpath('//product/active/text()', xml))::text = 't'
    FROM xmldata
    RETURNING code                                                     -- 1
)
INSERT INTO barcodes (barcode, product_code)
SELECT 
    unnest(xpath('//barcode/text()', xd.barcodes)),                    -- 4
    ip.code
FROM (
    SELECT 
        unnest(xpath('//product/code/text()', xml))::text as code,     -- 2
        unnest(xpath('//product/barcodes', xml)) as barcodes
    FROM xmldata
)xd
JOIN insert_products ip                                                -- 3
ON xd.code = ip.code

借助CTE,可以创建两个链接的INSERT语句。因此,您可以将代码作为第一条语句的RETURNING值获取。

因此,您可以根据产品代码搜索正确的条形码,以创建第二个INSERT语句的插入数据。

  1. 像您一样插入产品数据。但是返回产品代码。
  2. 再次选择产品代码,并将条形码数据转换为XML。
  3. 将插入的产品与原始数据结合起来,以将插入的代码分配给正确的条形码。
  4. 提取条形码数据并将其插入到条形码表中。

结果

Table products:

code   name    active
0001   Prod1   t
0002   Prod2   f

----------------------

Table barcodes:

barcode   product_code
0001666   0001
6660001   0001
0000420   0002

从技术上讲,如果产品插入物中没有任何过滤器,则可以保护连接部分的安全,因为在两个步骤中,您都在处理同一XML的全部数据。仅当您要过滤掉某些产品并且不想存储过滤出的条形码时,联接才有意义。

demo:db<>fiddle without join

demo:db<>fiddle with join and filter


通知如何解决boolean问题:

unnest(xpath('//product/active/text()', xml))::text = 't'

将XML内容转换为类型text,并将其与您的TRUE值进行比较。比较得出boolean

编辑:在您的情况下,这可以更简单地完成:您不需要进行比较,而只需进行第二次强制转换:

unnest(xpath('//product/active/text()', xml))::text::boolean

答案 1 :(得分:0)

-- TestQuery 使用示例数据从嵌套的 XML 中获取信息表

    WITH xmldata AS ( SELECT '<products>
                <product>
                    <code>A001</code>
                    <name>ProductA1</name>
                    <active>t</active>
                </product>
                <product>
                    <code>B002</code>
                    <name>ProductA2</name>
                    <active>f</active>
                </product>
             </products>'::xml)
SELECT  unnest(xpath('//product/code/text()', xml)) as code,
    unnest(xpath('//product/name/text()', xml)) as name,
    unnest(xpath('//product/active/text()', xml))::text = 't' as status
FROM xmldata;