Unnest (xpath ()) неправильно определяет значения NULL - PullRequest
0 голосов
/ 01 мая 2018

PostgreSQL версии 9.6 с использованием расширения xml2. Я пытаюсь извлечь строки из XML и вставить их в таблицу postgreSQL. Вот сокращенный пример:

ROLLBACK;
BEGIN;
DO $$
DECLARE 
    v_xml xml;
    v_record RECORD;
BEGIN
v_xml := '<?xml version="1.0" encoding="UTF-16"?>
<root>
    <table>
        <row><a>1</a><b>2</b><c>3</c></row>
        <row><a></a><b>5</b><c>6</c></row>
        <row><a>7</a><b>8</b><c>9</c></row> 
    </table>
</root>'::text;

CREATE TEMPORARY TABLE temptable( col_a text, col_b text, col_c text ) ON COMMIT DROP;
INSERT INTO temptable VALUES
(
    unnest(xpath('/root/table/row/a/text()', v_xml))::text,
    unnest(xpath('/root/table/row/b/text()', v_xml))::text,
    unnest(xpath('/root/table/row/c/text()', v_xml))::text
);

-- display table contents
FOR v_record IN SELECT * FROM temptable LOOP
    RAISE NOTICE 'col_a: % col_b: % col_c: %', v_record.col_a, v_record.col_b, v_record.col_c;
END LOOP;
END $$;

Это прекрасно работает, когда нет значений NULL:

NOTICE:  col_a: 1 col_b: 2 col_c: 3
NOTICE:  col_a: 4 col_b: 5 col_c: 6
NOTICE:  col_a: 7 col_b: 8 col_c: 9

Однако для отсутствующих или NULL-значений метод unnest () не распознает их должным образом и использует следующее значение в виде массива столбцов (который следует прочитать для строки next .

Чтобы продемонстрировать, измените XML следующим образом (то есть обнулите прежние значения 4 и 9 или полностью удалите элементы):

<table>
    <row><a>1</a><b>2</b><c>3</c></row>
    <row><a></a><b>5</b><c>6</c></row>
    <row><a>7</a><b>8</b><c></c></row>  
</table>

Теперь выдается следующий (ошибочный) вывод:

NOTICE:  col_a: 1 col_b: 2 col_c: 3
NOTICE:  col_a: 7 col_b: 5 col_c: 6
NOTICE:  col_a: 1 col_b: 8 col_c: 3
NOTICE:  col_a: 7 col_b: 2 col_c: 6
NOTICE:  col_a: 1 col_b: 5 col_c: 3
NOTICE:  col_a: 7 col_b: 8 col_c: 6

Некоторые операторы отладки показали, что три неопознанных массива столбцов: {1, 7}, {2, 5, 8} и {3, 6}. Нет заполнителей NULL для использования в качестве значений столбца при вставке данной строки.

Есть ли другой способ реализации unnesting, который будет правильно учитывать нулевые или отсутствующие значения узла?

1 Ответ

0 голосов
/ 01 мая 2018

Это не проблема с UNNEST, это проблема с (или, скорее, из-за) xpath, которая, по-видимому, не включает значения NULL в возвращаемом массиве.

SELECT XPATH('/root/table/row/a/text()', '<root><table><row><a>1</a><a></a><a>3</a></row></table></root>'::XML) возврат {1,3}

Один из способов обойти это - сначала выполнить xpath для элементов, а затем получить доступ к значениям:

SELECT (XPATH('/a/text()', u))[1]
FROM UNNEST(XPATH('/root/table/row/a', '<root><table><row><a>1</a><a></a><a>3</a></row></table></root>'::XML)) u

Возвращает 3 строки (вторая - NULL):

1

3
...