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用作列值。
是否有其他方法可以实现能够正确解释空值或缺少节点值的取消?
答案 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