我有一个可以使用for循环的解决方案,但是这种方法效率低下且性能不佳。我是初次使用收藏,还无法在互联网上找到答案。谁能指出我正确的方向? 这是我要实现的目标的简化版本。
DECLARE
TYPE rec_numbers IS RECORD
(
DIGIT NUMBER,
ENGLISH VARCHAR2 (10),
FRENCH VARCHAR2(10),
ITALIAN VARCHAR2(10)
);
TYPE tab_numbers IS TABLE OF rec_numbers;
blk_num tab_numbers;
blk_num2 tab_numbers;
BEGIN
SELECT 1 DIGIT, 'ONE' ENGLISH, NULL FRENCH, NULL ITALIAN
BULK COLLECT INTO blk_num
FROM DUAL;
SELECT 1 DIGIT, NULL ENGLISH, 'UN' FRENCH, 'UNO' ITALIAN
BULK COLLECT INTO blk_num2
FROM DUAL;
FOR i IN blk_num.FIRST .. blk_num.LAST LOOP
FOR j IN blk_num2.FIRST .. blk_num2.LAST LOOP
IF blk_num(i).digit = blk_num2(j).digit THEN
blk_num(i).french := blk_num2(j).french;
blk_num(i).italian := blk_num2(j).italian;
END IF;
END LOOP;
END LOOP;
END;
答案 0 :(得分:2)
嵌套循环可能很慢。如果blk_num
和blk_num2
都有1000条记录,则您正在执行1000x1000 = 1百万次迭代。那就是O(n ^ 2)的表现。
在加载blk_num2
并将其转换为关联数组后,可以将其降至O(n)。然后,您无需遍历blk_num2
中的所有条目,而只需通过其索引值要求它即可找到您要查找的条目。
这是我的意思的示例:
DECLARE
TYPE rec_numbers IS RECORD
(
DIGIT NUMBER,
ENGLISH VARCHAR2 (10),
FRENCH VARCHAR2(10),
ITALIAN VARCHAR2(10)
);
TYPE tab_numbers IS TABLE OF rec_numbers;
blk_num tab_numbers;
blk_num2 tab_numbers;
-- Define an associative array to copy blk_num2 into.
-- Note: I did not INDEX BY PLS_INTEGER because I do not know how big DIGIT can be.
-- if DIGIT will always fit into a PLS_INTEGER, you can use that instead.
TYPE assoc_numbers IS TABLE OF rec_numbers INDEX BY VARCHAR2(30);
blk_num2_aa assoc_numbers;
BEGIN
SELECT 1 DIGIT, 'ONE' ENGLISH, NULL FRENCH, NULL ITALIAN
BULK COLLECT INTO blk_num
FROM DUAL;
SELECT 1 DIGIT, NULL ENGLISH, 'UN' FRENCH, 'UNO' ITALIAN
BULK COLLECT INTO blk_num2
FROM DUAL;
-- Copy blk_num2 into blk_num2_aa
FOR i in blk_num2.FIRST..blk_num2.LAST LOOP
blk_num2_aa(to_char(blk_num2(i).digit)) := blk_num2(i);
END LOOP;
FOR i IN blk_num.FIRST .. blk_num.LAST LOOP
-- Find the match based on the associative array's index value
IF blk_num2_aa.exists(to_char(blk_num(i).digit)) THEN
blk_num(i).french := blk_num2_aa(to_char(blk_num(i).digit)).french;
blk_num(i).italian := blk_num2_aa(to_char(blk_num(i).digit)).italian;
END IF;
END LOOP;
END;
答案 1 :(得分:2)
您还没有提到为什么这里需要收藏。如果您将TYPE
和集合定义为架构对象,则可以使用TABLE
函数执行简单的联接查询,以完全执行您的for循环。
CREATE OR REPLACE
TYPE rec_numbers AS OBJECT
( digit NUMBER,
english VARCHAR2(10),
french VARCHAR2(10),
italian VARCHAR2(10) );
/
CREATE OR REPLACE TYPE tab_numbers AS
TABLE OF rec_numbers;
/
代码
SET SERVEROUTPUT ON
DECLARE
blk_num tab_numbers;
blk_num2 tab_numbers;
blk_num3 tab_numbers;
BEGIN
SELECT rec_numbers(1,'ONE',NULL,NULL) BULK COLLECT
INTO blk_num
FROM dual;
SELECT rec_numbers(1,NULL,'UN','UNO') BULK COLLECT
INTO blk_num2
FROM dual;
SELECT rec_numbers
( a.digit,
a.english,
COALESCE(b.french,a.french ),
COALESCE(b.italian,a.italian)
) BULK COLLECT
INTO blk_num3
FROM TABLE ( blk_num ) a
LEFT JOIN TABLE ( blk_num2 ) b
ON a.digit = b.digit;
blk_num := blk_num3;
for i in 1..blk_num.count
loop
dbms_output.put_line(blk_num(i).digit ||','||blk_num(i).english
||','||blk_num(i).french||','||blk_num(i).italian
);
END LOOP;
END;
/
输出
1,ONE,UN,UNO
PL/SQL procedure successfully completed.
答案 2 :(得分:1)
怎么样?
update (select * from table(blk_num )) a
set (FRENCH, ITALIAN) =
(select FRENCH, ITALIAN
from table(blk_num2) b
where a.DIGIT = b.DIGIT);