从PL/SQL变量一次一个地添加元素到集合变量?

 奋斗的筱清年 发布于 2023-02-07 18:51

我有一个用SQL Server编写的T-SQL例程.我们正在迁移到Oracle,因此我尝试将其移植到PL/SQL.这是T-SQL例程(简化); 请注意使用表值变量,在Oracle中,它将成为"嵌套表"类型的PL/SQL变量.我的问题的主要内容是在PL/SQL中使用这种"集合"对象的最佳方法.移植代码中的几个操作(下面的第二个代码示例)非常笨拙,在SQL Server原始版本中它们似乎更容易:

DECLARE @MyValueCollection TABLE( value VARCHAR(4000) );
DECLARE @valueForThisRow VARCHAR(4000);

DECLARE @dataItem1Val INT, @dataItem2Val INT, @dataItem3Val INT, @dataItem4Val INT;
DECLARE theCursor CURSOR FAST_FORWARD FOR
  SELECT DataItem1, DataItem2, DataItem3, DataItem4 FROM DataTable;

OPEN theCursor;

FETCH NEXT FROM theCursor INTO @dataItem1Val, @dataItem2Val, @dataItem3Val, @dataItem4Val;

WHILE @@FETCH_STATUS = 0
BEGIN
  -- About 50 lines of logic that evaluates @dataItem1Val, @dataItem2Val, @dataItem3Val, @dataItem4Val and constructs @valueForThisRow
  SET @valueForThisRow = 'whatever';

  -- !!! This is the row that seems to have no natural Oracle equivalent
  INSERT INTO @MyValueCollection VALUES(@valueForThisRow);  

  FETCH NEXT FROM theCursor INTO @dataItem1Val, @dataItem2Val, @dataItem3Val, @dataItem4Val;
END;

CLOSE theCursor;
DEALLOCATE theCursor;

-- !!! output all the results; this also seems harder than it needs to be in Oracle
SELECT * FROM @MyValueCollection;

我已经能够移植几乎所有东西,但在两个地方(参见代码中的注释),逻辑比旧的SQL Server方式复杂得多,我想知道在Oracle中是否会有更优雅的东西那种躲避我的方式:

set serveroutput on; -- needed for DBMS_OUTPUT; see below

DECLARE
  TYPE StringList IS TABLE OF VARCHAR2(4000);
  myValueCollection StringList;
  dummyTempCollection StringList; -- needed for my kludge; see below
  valueForThisRow VARCHAR2(4000);
BEGIN
  -- build all the sql statements
  FOR c IN (
    SELECT DataItem1, DataItem2, DataItem3, DataItem4 FROM DataTable;
  )
  LOOP
    -- About 50 lines of logic that evaluates c.DataItem1, c.DataItem2, c.DataItem3, c.DataItem4 and constructs valueForThisRow
    valueForThisRow := 'whatever';

    -- This seems way harder than it should be; I would rather not need an extra dummy collection
    SELECT valueForThisRow BULK COLLECT INTO dummyTempCollection FROM dual;    -- overwrites content of dummy temp
    myValueCollection := myValueCollection MULTISET UNION dummyTempCollection; -- merges into main collection

  END LOOP;

  -- output all the results... again, there's no shorter/easier/more-compact/single-line equivalent?
  IF myValueCollection.COUNT > 0
  THEN
    FOR indx IN myValueCollection.FIRST .. myValueCollection.LAST
    LOOP
       DBMS_OUTPUT.PUT_LINE(myValueCollection(indx));
    END LOOP;
  END IF;
END;
/

在此先感谢您的帮助!

1 个回答
  • 就个人而言,我将采用"50行逻辑",将其移动到您在SQL语句中调用的函数中,然后执行一个简单的BULK COLLECT操作将数据加载到本地集合中.

    假设您确实希望逐个元素地将数据加载到集合中,您可以简化加载集合的代码

    DECLARE
      TYPE StringList IS TABLE OF VARCHAR2(4000);
      myValueCollection StringList := StringList();
      valueForThisRow VARCHAR2(4000);
    BEGIN
      -- build all the sql statements
      FOR c IN (
        SELECT DataItem1, DataItem2, DataItem3, DataItem4 FROM DataTable;
      )
      LOOP
        -- About 50 lines of logic that evaluates c.DataItem1, c.DataItem2, c.DataItem3, c.DataItem4 and constructs valueForThisRow
        valueForThisRow := 'whatever';
    
        myValueCollection.extend();
        myValueCollection( myValueCollection.count ) := valueForThisRow;
      END LOOP;
    
      -- output all the results... again, there's no shorter/easier/more-compact/single-line equivalent?
      IF myValueCollection.COUNT > 0
      THEN
        FOR indx IN myValueCollection.FIRST .. myValueCollection.LAST
        LOOP
           DBMS_OUTPUT.PUT_LINE(myValueCollection(indx));
        END LOOP;
      END IF;
    END;
    /
    

    如果将集合声明为关联数组,则可以避免调用extend以增加集合的大小.如果您知道要加载到集合中的元素数量,则可以将其传递给extend循环外的单个调用.潜在地,您还可以消除valueForThisRow局部变量,并仅对集合中的元素进行操作.

    至于处理集合的代码,你真正想做的是什么?生产代码写入dbms_output并期望任何人在正常处理期间都能看到输出是非常不寻常的.这将影响您编写该代码的方式.假设你的意图真的只是打电话dbms_output,知道通常会将数据发送到以太网

    FOR indx IN 1 .. myValueCollection.count
    LOOP
      dbms_output.put_line( myValueCollection(indx) );
    END LOOP;
    

    当您拥有密集集合时(所有索引在1和count集合之间存在且具有值),这都适用.如果你可能有一个稀疏集合,你会想使用FIRST,NEXT以及LAST在一个循环,但是这是一个有点更多的代码.

    2023-02-07 18:53 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有