PLSQL:将数据从 XML 解析并插入到表中
Posted
技术标签:
【中文标题】PLSQL:将数据从 XML 解析并插入到表中【英文标题】:PLSQL: Parsing and inserting data from XML to tables 【发布时间】:2019-08-11 18:13:16 【问题描述】:我有以下表格:
create table TBL$ORDERS
(
order_num VARCHAR2(25),
employee VARCHAR2(100),
createddt VARCHAR2(20),
modifieddt VARCHAR2(20),
deleteddt VARCHAR2(20),
state VARCHAR2(15),
ts VARCHAR2(20),
nni VARCHAR2(20),
constraint pk_orders primary key (order_num)
);
create table TBL$METERS
(
order_num VARCHAR2(25),
xmlid VARCHAR2(5),
createddt VARCHAR2(20),
modifieddt VARCHAR2(20),
deleteddt VARCHAR2(20),
vendor VARCHAR2(25),
model VARCHAR2(25),
serial VARCHAR2(25),
constraint pk_meters primary key (order_num, xmlid),
constraint fk_orders foreign key (order_num) references TBL$ORDERS (order_num)
);
create table TBL$TESTS
(
order_num VARCHAR2(25),
meterxmlid VARCHAR2(5),
xmlid VARCHAR2(5),
createddt VARCHAR2(20),
testcount VARCHAR2(5),
successcount VARCHAR2(5),
test1 VARCHAR2(50),
test2 VARCHAR2(50),
test3 VARCHAR2(50),
test4 VARCHAR2(50),
constraint pk_tests primary key (order_num, meterxmlid, xmlid),
constraint fk_meters foreign key (order_num, meterxmlid) references TBL$METERS (order_num, xmlid)
);
我想用这段代码填充:
procedure PopulateTables(pXMLClob clob) is
begin
for recOrders in (
select *
from XMLTable(
'/Orders/Order'
passing XMLType(pXMLClob)
columns
order_num VARCHAR2(25) path '@order_num',
employee VARCHAR2(100) path '@employee',
createddt VARCHAR2(20) path '@createdDT',
modifieddt VARCHAR2(20) path '@modifiedDT',
deleteddt VARCHAR2(20) path '@deletedDT',
state VARCHAR2(15) path '@state',
ts VARCHAR2(20) path '@ts',
nni VARCHAR2(20) path '@nni',
Meters xmltype path 'Meter'
)
)
loop
insert into TBL$ORDERS(order_num, employee, createddt, modifieddt, deleteddt, state, ts, nni)
values (recOrders.order_num, recOrders.employee, recOrders.createddt, recOrders.modifieddt, recOrders.deleteddt, recOrders.state, recOrders.ts, recOrders.nni);
for recMeters in (
select *
from XMLTable(
'/Orders/Order'
passing XMLType(recOrders.Meters)
columns
xmlid VARCHAR2(5) path '@xmlid',
createddt VARCHAR2(20) path '@createdDT',
modifieddt VARCHAR2(20) path '@modifiedDT',
deleteddt VARCHAR2(20) path '@deletedDT',
vendor VARCHAR2(25) path '@vendor',
model VARCHAR2(25) path '@model',
serial VARCHAR2(25) path '@serial',
order_num VARCHAR2(25) path '@order_num',
tests xmltype path 'test'
)
)
loop
insert into TBL$METERS (order_num, xmlid, createddt, modifieddt, deleteddt, vendor, model, serial)
values (recOrders.order_num, recMeters.xmlid, recMeters.createddt, recMeters.modifieddt, recMeters.deleteddt, recMeters.vendor, recMeters.model, recMeters.serial);
for recTest in (
select *
from XMLTable(
'/Orders/Order'
passing XMLType(recMeters.Tests)
columns
xmlid VARCHAR2(5) path '@xmlID',
createddt VARCHAR2(20) path '@createdDT',
testcount VARCHAR2(5) path '@testCount',
successcount VARCHAR2(5) path '@successCount',
test1 VARCHAR2(50) path '@test1',
test2 VARCHAR2(50) path '@test2',
test3 VARCHAR2(50) path '@test3',
test4 VARCHAR2(50) path '@test4',
meter_xmlid VARCHAR2(5) path '@xmlID',
order_order_num varchar(25) path '@order_num'
)
)
loop
insert into TBL$TESTS (xmlid, createddt, testcount, successcount, test1, test2, test3, test4, meter_xmlid , order_order_num )
values (recTest.xmlid, recTest.createddt, recTest.testcount, recTest.successcount, recTest.test1, recTest.test2, recTest.test3, recTest.test4, recMeters.xmlid, recOrders.Order_num);
end loop;
end loop;
end loop;
commit;
end;
我在传递 XMLTYPE() 的行中遇到错误。
ora-00306 调用 XMLTYPE 时类型或参数的数量错误。
谁能告诉我如何解决这个问题?
【问题讨论】:
请将您的代码直接提供给 Stack Overflow 请添加完整的错误信息,包括行号。它也将有助于尽可能减少代码。代码越大,别人看的可能性就越小。 【参考方案1】:我确实制定了对您之前问题的答案,您已将其删除。我已经改变它以适应新的问题。问题都是一样的。
方法
在这些表之间建立关系 我需要使用 PK 和 FK 在这些表之间建立关系。
它不是那样工作的。我很欣赏你有一项任务,并且只专注于完成工作,但这种心态充满了问题。不仅是现在,还有未来会暴露的可预测和可预防的错误。
正确的做法是:
创建一个与自然宇宙相匹配(是地图)的数据库。为什么 ?因为宇宙的结构不会改变(内容会改变)。 这将使您的应用免受更改(来自 XML 端的更改)。 否则,每次 XML (a) 更改或 (b) 您发现错误(现在有一些错误!)并需要修复它时,您都必须更改数据库的结构。因此是代码。相反的是保持开发人员对数据的看法(您现在需要什么),这与现实世界几乎没有关系。在这种情况下,您永远不会真正了解数据的本来面目,您会将数据作为片段进行处理,并且会像玩壳游戏一样不断移动它们。
我有以下表格:
有第一个误解。这些不是表,这只是传入 XML 的定义。将它们视为表意味着您认为这是您需要在数据库中实现的最终产品。然后,对现实世界的感知以及数据如何表示它,就会丢失。
事实是,您有一个 XML 文件定义,它不是 1::1 的表,也不是 1::1 现实世界有人告诉我,一个订单可以有多个仪表,一个仪表可以有多个测试。 但是,我在这些表中看不到可以建立关系的属性
那是因为没有(在 XML 中)。同样,您必须再次弄清楚,最好的选择是现实世界,而不是 XML。
meter表中应该有order_num字段,Test表中应该有meter_id。
如果您想要一个 1960 年代的记录归档系统,那没关系,这是“理论家”和追随他们的作者错误地宣传为“关系”的东西。高度受限,没有完整性。
我看到您现在已经添加了这些字段。
这是一个很好的例子,说明它没有任何完整性。
如何[正确]识别仪表? 你会说primary key ( order_num, xmlid )
,
但那是错误的,xmlid
只是 XML 开发人员分配给Orders
下的行的行号
如果您使用它,您将在一天记录仪表 X 和仪表 X 的读数,并在第二天记录仪表 X 和仪表 Y 的读数。反之亦然。
即使他们知道存在问题,即 [对于任何给定订单] 领域中的仪表不断变化(注意 modifieddt
和 deleteddt
)
他们给了你( vendor, model, serial )
这是 Meter 唯一有效的 PK(如果您希望防止可预防的错误)
xmlid
与您完全无关(仅与 XML 开发人员相关),可以从 XML 文件中排除
关系数据库
我可以提供您执行此任务所需的关系数据库。它具有完整的数据完整性。但这是第一次剪辑,并不完整。为什么 ?因为 XML 文件中存在严重错误。一旦你修复了这些错误,我就可以调整数据库,它就会完成。
“测试”可能不是一个好的标签。测试阶段完成后,将是Meter的读数 一个读数中似乎有四个样本 员工可能没那么重要,我给它是为了完整 我所有的数据模型都在 IDEF1X 中呈现,这是自 1993 年以来用于建模关系数据库的标准 我的IDEF1X Introduction 是必读。错误是 XML 文件
(参考已删除问题中给出的 XML 文件。
不得让serial
为空
Test
(更好的是test1..4
)必须通过(供应商、型号、序列号)识别适用的仪表
每个 Test
中的 4 个样本未标准化,应该有 4 个 XML 记录(每个 test1..4
)
test4
有日期时间,但没有 test1..3
test4
中的日期时间需要为格式 23(与其他日期时间相同)
员工识别订单还是抄表?我模拟了前者。
最后,一旦删除了重复和愚蠢,XML file that is required for the purpose 比他们给你的要简单得多。
解析 XML
但是,我的解析器 xml 程序有问题。您能否阅读我的程序并帮助我将 FK 也包括在内?
没有。这超出了这个问题的范围。提出一个新问题,并让该领域的人帮助您。
链接失败。
坦率地说,我从不关心那些声称解析 XML 的产品,它们比它们的价值更麻烦,而且当它们失败时,你必须自己摆弄它。我只是编写代码来解析 XML,这很简单。我将awk
用于所有此类工作,所有ETL。
perl
更好,因为它有一个到数据库的 PLSQL-Client 连接,但它需要一些设置。我认为 Oracle 变体是oraperl
。
PLSQL 过程
我没有 Oracle 专业知识,因此无法在代码级别对此做出回应。但是让我说,如果你理解我这里的答案,并实现与现实世界相匹配的表,你的代码会很简单。
首先要理解的是,您不能只将 XML 文件导入数据库(使用 XML 解析器或 OracleLOOP
)。为什么 ?因为,同样,XML 与现实世界或数据库不匹配(而数据库与现实世界匹配)。
您需要的是普通的 SQL ACID 事务(在 Oracle 中,通常作为 proc 实现)。
XML 文件中有很多信息,尚未明确说明:
当有新订单或计量表进来时,您需要先IF NOT EXISTS ... INSERT
,然后INSERTing
读数和样本
当 Order 或 Meter 中的 modifieddt
或 deleteddt
发生变化时,您需要UPDATE
这些列
同样,这就是我使用awk
解析 XML 文件并生成一系列正确、适用的 SQL 命令的原因。
【讨论】:
以上是关于PLSQL:将数据从 XML 解析并插入到表中的主要内容,如果未能解决你的问题,请参考以下文章
PLSQL:将数据从一个表中插入可能的环境到另一个表,同时保持 from_table 名称动态
如何将 PHP 数据从数据库发送回 JQuery 并插入到表中