将 XML 数据(我从网页获取的数据)插入 PostgreSQL 数据库的最佳方式是什么?
我正在使用 Java,需要一些帮助才能找到将这些数据读入数据库的好方法。
原文由 user622194 发布,翻译遵循 CC BY-SA 4.0 许可协议
将 XML 数据(我从网页获取的数据)插入 PostgreSQL 数据库的最佳方式是什么?
我正在使用 Java,需要一些帮助才能找到将这些数据读入数据库的好方法。
原文由 user622194 发布,翻译遵循 CC BY-SA 4.0 许可协议
我有一个工作实现,我在 PostgreSQL 中完成 所有 操作,无需额外的库。
CREATE OR REPLACE FUNCTION f_xml_extract_val(text, xml)
RETURNS text AS
$func$
SELECT CASE
WHEN $1 ~ '@[[:alnum:]_]+$' THEN
(xpath($1, $2))[1]
WHEN $1 ~* '/text()$' THEN
(xpath($1, $2))[1]
WHEN $1 LIKE '%/' THEN
(xpath($1 || 'text()', $2))[1]
ELSE
(xpath($1 || '/text()', $2))[1]
END;
$func$ LANGUAGE sql IMMUTABLE;
上面的实现不处理一个 xpath 中的 多个属性。这是 f_xml_extract_val()
的 重载 版本。使用第三个参数,您可以选择 one
(第一个), all
或 dist
(不同的)值。多个值聚合成逗号分隔的字符串。
CREATE OR REPLACE FUNCTION f_xml_extract_val(_path text, _node xml, _mode text)
RETURNS text AS
$func$
DECLARE
_xpath text := CASE
WHEN $1 ~~ '%/' THEN $1 || 'text()'
WHEN lower($1) ~~ '%/text()' THEN $1
WHEN $1 ~ '@\w+$' THEN $1
ELSE $1 || '/text()'
END;
BEGIN
-- fetch one, all or distinct values
CASE $3
WHEN 'one' THEN RETURN (xpath(_xpath, $2))[1]::text;
WHEN 'all' THEN RETURN array_to_string(xpath(_xpath, $2), ', ');
WHEN 'dist' THEN RETURN array_to_string(ARRAY(
SELECT DISTINCT unnest(xpath(_xpath, $2))::text ORDER BY 1), ', ');
ELSE RAISE EXCEPTION
'Invalid $3: >>%<<', $3;
END CASE;
END
$func$ LANGUAGE plpgsql;
COMMENT ON FUNCTION f_xml_extract_val(text, xml, text) IS '
Extract element of an xpath from XML document
Overloaded function to f_xml_extract_val(..)
$3 .. mode is one of: one | all | dist'
称呼:
SELECT f_xml_extract_val('//city', x, 'dist');
目标表名称: tbl
;原始的。关键: id
:
CREATE OR REPLACE FUNCTION f_sync_from_xml()
RETURNS boolean AS
$func$
DECLARE
datafile text := 'path/to/my_file.xml'; -- only relative path in db dir
myxml xml := pg_read_file(datafile, 0, 100000000); -- arbitrary 100 MB
BEGIN
-- demonstrating 4 variants of how to fetch values for educational purposes
CREATE TEMP TABLE tmp ON COMMIT DROP AS
SELECT (xpath('//some_id/text()', x))[1]::text AS id -- id is unique
, f_xml_extract_val('//col1', x) AS col1 -- one value
, f_xml_extract_val('//col2/', x, 'all') AS col2 -- all values incl. dupes
, f_xml_extract_val('//col3/', x, 'dist') AS col3 -- distinct values
FROM unnest(xpath('/xml/path/to/datum', myxml)) x;
-- 1.) DELETE?
-- 2.) UPDATE
UPDATE tbl t
SET ( col_1, col2, col3) =
(i.col_1, i.col2, i.col3)
FROM tmp i
WHERE t.id = i.id
AND (t.col_1, t.col2, t.col3) IS DISTINCT FROM
(i.col_1, i.col2, i.col3);
-- 3.) INSERT NEW
INSERT INTO tbl
SELECT i.*
FROM tmp i
WHERE NOT EXISTS (SELECT 1 FROM tbl WHERE id = i.id);
END
$func$ LANGUAGE plpgsql;
如果插入的行已经存在并在这种情况下进行 更新,此实现将检查主键。仅插入新行。
我使用临时临时表来加快该过程。
使用 Postgres 8.4、9.0 和 9.1 进行测试。
XML 必须格式正确。
pg_read_file()
有限制。 手册:
这些功能的使用仅限于超级用户。
和:
只能访问数据库集群目录和
log_directory
中的文件。
所以你必须把你的源文件放在那里 - 或者创建一个符号链接到你的实际文件/目录。
或者 您可以根据您的情况通过 Java 提供文件(我在 Postgres 中完成了所有操作)。
或者 您可以将数据导入临时表的 1 行的 1 列,然后从那里获取。
或者 您可以使用 lo_import
就像 在 dba.SE 上的相关答案中所 演示的那样。
Scott Bailey 的 这篇博文对我有所帮助。
原文由 Erwin Brandstetter 发布,翻译遵循 CC BY-SA 4.0 许可协议
15 回答8.4k 阅读
8 回答6.2k 阅读
1 回答4k 阅读✓ 已解决
3 回答6k 阅读
3 回答2.2k 阅读✓ 已解决
2 回答3.1k 阅读
2 回答3.8k 阅读
Postgres 有(感谢 Daniel Lyons 指出) 本地 XML 支持,你可以用它来存储你的表。但是,如果您想要手动分解 XML 数据,则有不同的可能性在数据库中表示 XML 数据。第一个问题应该是,如果您想要一个非常通用的解决方案,它将能够存储任何 XML 文档或特定于您的域的文档(即只允许特定结构的 XML 文档)。取决于此,您将拥有一个非常灵活、通用的表示,但它更难查询(所需的 SQL 将非常复杂)。如果您有更具体的方法,查询会更简单,但是每次要存储另一种类型的文档或向现有文档添加字段时,都需要创建新表或向现有表添加新属性;因此更改架构将更加困难(这是 XML 的一大优势)。 此演示文稿 应该让您了解不同的可能性。
此外,您可能会考虑切换到某些支持 Xquery 的数据库,例如 DB2 。使用 XQuery(一种旨在处理 XML 的语言)进行本机查询的能力将大大简化事情。
更新:鉴于您的评论,您的 XML 数据( 您链接到)是完全相关的。可以1:1映射到下表:
所以任何
mynt
标签都是表中的一条记录,相应的子标签是属性。我从你的数据中收集的数据类型,它们可能是错误的。主要问题是,IMO,没有自然主键,所以我添加了一个自动生成的主键。