Postgresql XML-таблица с вложенными данными - PullRequest
0 голосов
/ 27 октября 2018

У меня есть какой-то 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
);

и это работает для продуктов, но есть ли разумный способ заполнить таблицу штрих-кодов ссылками на код продукта в том же утверждении?

КСТАТИ. Я не смог найти приведение, которое работало бы для вставки в логическое «активное», какие-либо указатели?

Заранее спасибо, Nik

1 Ответ

0 голосов
/ 30 октября 2018

демо: дБ <> скрипка

Тест 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. Объединение имеет смысл только в том случае, если вы хотите отфильтровать некоторые продукты и не хотите хранить отфильтрованные штрих-коды.

демо: дб <> скрипка без соединения

демо: дБ <> скрипка с соединением и фильтром


Обратите внимание как вы можете решить вашу boolean проблему:

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

Преобразуйте содержимое XML в тип text и сравните его с вашим значением TRUE. Сравнение выдает boolean.

Редактировать: В вашем случае это может быть сделано еще проще: вам не нужно сравнение, а только второе приведение:

unnest(xpath('//product/active/text()', xml))::text::boolean
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...