2015-11-12 44 views
-1

我在SQL中编写了一个简单的游标,如下所示。在这里我期待它会从测试中获取所有行,并根据行数将硬编码值添加到test2表中。游标无限期运行

DECLARE 
    CURSOR customers is 
    SELECT * FROM test; 
BEGIN 
    OPEN customers; 
    LOOP 
    insert into test2 values (2, 3, 3); 
    END LOOP; 
    CLOSE customers; 
END; 
/

当我在sql提示符下执行它时,它会无限期地运行。 我在这里做错了什么?

+1

我希望这是一个学习练习,而不是你在生产代码中试图做的事情?因为在现实中,你永远不会把它写成一个通过游标的循环。相反,你应该这样做:'插入test2从测试中选择2,3,3'(如果需要,可以将其放入pl/sql过程中)。 – Boneist

回答

3

您可以使用FOR LOOP

DECLARE 
    CURSOR customers IS 
    SELECT * FROM test; 
BEGIN 
    FOR i IN customers 
    LOOP 
    insert into test2 values (2, 3, 3); 
    END LOOP; 
END; 
/

,或者您需要添加EXIT CONDITION监守你的循环是(无限期):

DECLARE 
    CURSOR customers is 
    SELECT * FROM test; 

    l_customer customers%ROWTYPE; 
BEGIN 
    OPEN customers; 
    LOOP 
    FETCH customers INTO l_customer; 
    EXIT WHEN customers%NOTFOUND; 

    insert into test2 values (2, 3, 3); 
    END LOOP; 
    CLOSE customers; 
END; 
/

编辑:

由于Lalit Kumar B中提到的评论,你可以使用:

BEGIN 
    FOR i IN (SELECT * FROM test) 
    LOOP 
     insert into test2 values (2, 3, 3); 
    END LOOP; 
END; 

欲了解更多信息阅读Working with Cursors by Steven Feuerstein

+1

谢谢,它工作。 –

+2

您的第一个使用显式游标的匿名块,然后使用for循环可以使用** CURSOR FOR LOOP **一步完成。 '为我在(选择*从测试)LOOP ...' –

+0

@LalitKumarB好点 – lad2025

2

我认为你使用游标的方式不正确。在下面我编辑了你的代码..你需要添加退出条件来终止循环。

DECLARE 
    CURSOR customers is 
    SELECT * FROM test; 
    cus2 customers%rowtype; 
BEGIN 
    OPEN customers; 
    LOOP 
    FETCH customers INTO cus2; 
    EXIT WHEN customers%NOTFOUND; 
    insert into test2 values (2, 3, 3); 
    END LOOP; 
    CLOSE customers; 
END; 
/

根据您的要求修改上述块。

+0

它给了我'这种表达的类型的声明是不完整或畸形' –

+0

@PrinceManiGupta我已更新我的查询,请现在检查。 – Buddi

+1

感谢@Tarun快速回复。 –

3

我宁愿避免使用显式游标和使用游标循环

BEGIN 
    FOR i IN 
    (SELECT * FROM test 
) 
    LOOP 
    <do something> 
    INSERT INTO test2 VALUES ...; 
    END LOOP; 
END; 
/

记住,一个循环会做插入行由行又名慢的慢

As @Boneist提到,cursor for loop比显式游标更好。在最近的Oracle版本中,它通过内部执行bulk collect limit 100以更好的方式进行了优化。

但是,这不只是散装收集,我们正在处理的操作我们,我们有获取逐步阵列上随后做。我们可以通过使用FORALL声明以及BULK COLLECT来进一步提高性能。

IMO,最好的会在纯SQL使用INSERT INTO table SELECT..。还有很多其他因素,但它不在OP的问题范围之内。

+0

“您可以使用BULK COLLECT来提高性能。” <---我讨厌这种缓慢缓慢的做法。主要是因为通常(就像在OP的例子中),根本不需要游标,部分原因是Oracle无论如何都优化了一个游标循环来执行批量收集限制100。 – Boneist

+0

@Boneist ..你解释了为什么我更喜欢'cursor for loop' over'explicit cursor'。另一部分关于'BULK COLLECT',OP正在做一个**行的**插入,这可以进一步改进。我同意你的看法,在最近的版本中,'cursor for loop'确实有一个批量收集限制100'。我在最近的版本中看到的是,cursor for循环中的批量限制100是很好的,但是随着** FORALL **的批量获取甚至更好。当我得到时间时,我会重新回答我的答案。国际海事组织,我宁愿做一个简单的插入。感谢您提出这个问题:-) –