Unnest(xpath())无法正确识别NULL值

时间:2018-05-01 19:20:11

标签: xml postgresql plpgsql

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值,unfst()无法正确识别它们并使用其列数组的下一个值(应该为 next 行读取。

要演示,请按如下方式修改XML(即将前4和9值设为null,或完全删除元素):

<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

一些调试语句显示三个unnested列数组为{1,7},{2,5,8}和{3,6}。插入给定行时,没有占位符NULL用作列值。

是否有其他方法可以实现能够正确解释空值或缺少节点值的取消?

1 个答案:

答案 0 :(得分:2)

这不是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