Rob*_*t N 2 oracle plsql oracle11g
我有一个用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;
Run Code Online (Sandbox Code Playgroud)
我已经能够移植几乎所有东西,但在两个地方(参见代码中的注释),逻辑比旧的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;
/
Run Code Online (Sandbox Code Playgroud)
在此先感谢您的帮助!
就个人而言,我将采用"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;
/
Run Code Online (Sandbox Code Playgroud)
如果将集合声明为关联数组,则可以避免调用extend以增加集合的大小.如果您知道要加载到集合中的元素数量,则可以将其传递给extend循环外的单个调用.潜在地,您还可以消除valueForThisRow局部变量,并仅对集合中的元素进行操作.
至于处理集合的代码,你真正想做的是什么?生产代码写入dbms_output并期望任何人在正常处理期间都能看到输出是非常不寻常的.这将影响您编写该代码的方式.假设你的意图真的只是打电话dbms_output,知道通常会将数据发送到以太网
FOR indx IN 1 .. myValueCollection.count
LOOP
dbms_output.put_line( myValueCollection(indx) );
END LOOP;
Run Code Online (Sandbox Code Playgroud)
当您拥有密集集合时(所有索引在1和count集合之间存在且具有值),这都适用.如果你可能有一个稀疏集合,你会想使用FIRST,NEXT以及LAST在一个循环,但是这是一个有点更多的代码.
| 归档时间: |
|
| 查看次数: |
11312 次 |
| 最近记录: |