【问题标题】:Oracle PL/SQL - Heterogeneous iterable data structureOracle PL/SQL - 异构可迭代数据结构
【发布时间】:2021-03-01 21:17:06
【问题描述】:

我正在寻找一种方法来在 Oracle PL/SQL 中使用异构数据定义数据结构,并且我可以在其中迭代值。

不知道是否有可能,就我所见,数组和关联数组等数据结构只允许所有元素属于同一类型。

我的用例是我收到一堆值,必须处理它们并将它们插入到表中。

我想要这样的东西:

DECLARE
   type books is record
      (title varchar(50)   := myvar1,
      author varchar(50)   := myvar2,
      subject varchar(100) := myvar3,
      book_id number       := myvar4);
BEGIN
  FOR item IN ('SELECT * FROM books')
  LOOP
    /* Here I would access each individual item key and value (title, author...) */
    my_function(item.key, item.value)
  END LOOP;
END;

请注意,在上面的示例中,我想迭代字段,而不是记录,只有一条记录。

所以我想要一些与 Javascript 中的对象非常相似的东西:

var obj = {
  title: 'Romeo and Juliet',
  author: 'Some dude',
  subject: 'Romance',
  book_id: 332764
};
    
for (const prop in obj) {
  console.log(`obj.${prop} = ${obj[prop]}`);
}

这适用于 Oracle 19c。

有没有办法做到这一点?

【问题讨论】:

  • 我不确定我是否完全按照您的意愿行事。您可以使用dbms_sql 执行动态查询,描述结果以找出列和数据类型,然后对其进行迭代。但是从您的问题来看,您需要这种复杂程度的东西对我来说并不明显。在您的循环中,您可以简单地引用item.titleitem.author(假设titleauthorbooks 表中的列)。如果创建books类型的局部变量,同样可以引用variable.titlevariable.author
  • @JustinCave 如果我必须使用item.titleitem.author... 我将不得不重复同样的事情,比如 20 次。有 20 行带有 INSERT 语句的不同行看起来很难看,我想要 DRY 代码。此外,将来,如果我想插入另一个项目,只需将其添加到结构中并完成。
  • 但是你说你需要处理这些值并将它们插入到一个表中。根据值的来源和处理方式,您可能正在寻找动态 SQL。你可以做一个简单的execute immediate 或者你可能需要使用dbms_sql。不过,这不会涉及 PL/SQL 记录,我不确定这是否是必需的。
  • @JustinCave 我明白了,所以在 PL/SQL 中似乎没有简单的方法可以做到这一点:/ 我真的期待会有一个简单的方法。
  • SQL 和 PL/SQL 是强数据类型的,严格遵守数据结构。那是因为数据完整性是首要指令。是的,在向表中插入数据时,这为开发人员增加了一些工作量。但这也意味着在检索数据时,开发人员的工作量会减少。最重要的是,这意味着我们的用户可以依赖数据的稳定性和正确性。

标签: arrays oracle data-structures plsql iterable


【解决方案1】:

也许如下。在架构级别创建一个定义了属性的 Books 对象,然后创建该对象的集合。

create type books as object
      (title   varchar(50)    
      ,author  varchar(50)   
      ,subject varchar(100) 
      ,book_id number 
      );
  
create type table_of_books as 
    table of books;

然后,您可以像处理任何其他集合一样处理表格,但通过标准点 (.) 引用限定其中的项目。见Fiddle here

如果您需要已定义的默认值,请为您的对象定义创建一个constructor


为局部定义修订

declare
   type books is record
        (title   varchar(50)    
        ,author  varchar(50)   
        ,subject varchar(100) 
        ,book_id number 
        );      
   type table_of_books is 
      table of books;
   list_of_books table_of_books;    
begin
  dbms_output.enable;
  list_of_books := table_of_books(); -- initialize collection
  -- populates List
  list_of_books.extend(2);
  list_of_books(1) := books('First Book','Me','Simple ones',12345);
  list_of_books(2) := books('Another First','You','Advnnced ones',94321);  
  
   -- processing 

  dbms_output.put_line('Current List of ' || list_of_books.count || ' books');
  for item in 1 .. list_of_books.count  
  loop 
    /* Here I would access each individual item (title, author...) */
    dbms_output.put_line( 'ID: ' || list_of_books(item).book_id 
                        || ', Title: '  || list_of_books(item).title
                        || ', By: ' || list_of_books(item).author
                        ); 
                       
  end loop;
end;

为什么不使用本地定义。

你问它你可以创建但不是随处可见。是的,你可以,但为什么。您创建对象,这样您就不需要在每次需要它们时都创建它们。

此外,如果在 2 个过程中本地定义它们不是相同的定义,因此不能作为参数传递。在本地创建时,定义不能在 SQL 中使用。
但是对象,就像 Oracle 中的大多数东西一样,都有privileges,您可以使用它们来控制访问(或拒绝访问)。另一种选择是将定义与处理它们的过程和/的函数一起包装到一个包中。该控件通过对包的可访问性来控制可见性。

【讨论】:

  • 我喜欢这个。但是有没有办法不创建一个随处可见的类型?就像我们如何创建嵌套的子程序一样。
  • 是的,你可以,但是为什么呢?在模式上创建的想法是,您不必在每次需要时都定义它。但我更新了答案以显示本地版本以及为什么不这样做的一些理由。
  • 这不是我真正需要的,但很接近。我需要迭代字段,而不是记录。我将有一个单一的记录。我需要迭代获取字段名称和与其关联的值的字段。这样它就可以像具有异构数据的关联数组一样工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-15
  • 2016-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多