【问题标题】:PLSQL: Parsing and inserting data from XML to tablesPLSQL:将数据从 XML 解析并插入到表中
【发布时间】: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
  • 请添加完整的错误信息,包括行号。它也将有助于尽可能减少代码。代码越大,别人看的可能性就越小。

标签: xml parsing plsql procedure


【解决方案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 的读数。反之亦然。
    • 即使他们知道存在问题,即 [对于任何给定订单] 领域中的仪表不断变化(注意 modifieddtdeleteddt
    • 他们给了你( 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 也包括在内?

  1. 没有。这超出了这个问题的范围。提出一个新问题,并让该领域的人帮助您。

  2. 链接失败。

  3. 坦率地说,我从不关心那些声称解析 XML 的产品,它们比它们的价值更麻烦,而且当它们失败时,你必须自己摆弄它。我只是编写代码来解析 XML,这很简单。我将awk 用于所有此类工作,所有ETL。

    • perl 更好,因为它有一个到数据库的 PLSQL-Client 连接,但它需要一些设置。我认为 Oracle 变体是oraperl

PLSQL 过程

我没有 Oracle 专业知识,因此无法在代码级别对此做出回应。但是让我说,如果你理解我这里的答案,并实现与现实世界相匹配的表,你的代码会很简单。

  • 首先要理解的是,您不能只将 XML 文件导入数据库(使用 XML 解析器或 Oracle LOOP)。为什么 ?因为,同样,XML 与现实世界或数据库不匹配(而数据库与现实世界匹配)。
  • 您需要的是普通的 SQL ACID 事务(在 Oracle 中,通常作为 proc 实现)。
  • XML 文件中有很多信息,尚未明确说明:
    • 当有新订单或计量表进来时,您需要先
      IF NOT EXISTS ... INSERT,然后
      INSERTing 读数和样本
    • 当 Order 或 Meter 中的 modifieddtdeleteddt 发生变化时,您需要
      UPDATE 这些列

同样,这就是我使用awk 解析 XML 文件并生成一系列正确、适用的 SQL 命令的原因。

【讨论】:

    猜你喜欢
    • 2012-10-10
    • 2010-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-07
    相关资源
    最近更新 更多