虽然努力改善SP的可维护性在我们的一个系统,我决定,使用循环会比其值(表名在这种情况下)的阵列更好的硬编码并试图相应地重新分配代码,以便向系统添加或删除表格不需要编辑数组。撇开目前的循环(我知道反对他们的观点),任何人都可以解释发生了什么?甲骨文For循环存储过程中不循环
想象一下两个用户,SOURCEUSER和DestUser都在同一个数据库中,每个与他们在同一个表空间中的表。 SourceUser中的一堆存储过程将来自SourceUser的数据填充到DestUser中以用于报告目的。作为其中的一部分,要运行的第一个程序会丢弃DestUser中的所有表并重新创建它们。再次,不要在这里辩论这样做的相对优点。
SOURCEUSER具有降大任表和DestUser创建的任何表的权限。 DestUser中有一张我们想要保留的表格。所以,我的方法构建的SQL是这样的:
Begin
For T In (SELECT TABLE_NAME FROM all_tables WHERE TABLE_NAME != 'MIDBLOG' AND OWNER = sTarget_DB) Loop
Begin
Execute Immediate('Drop Table ' || sTarget_DB || '.' || T.TABLE_NAME);
Exception
When Others Then
--Don't care if we get an exception here as most likely the table wasn't there to be dropped in the first place.
NULL;
End;
End Loop;
End;
在这种情况下sTarget_DB设置为DestUser,这个代码正在对SOURCEUSER运行。
当程序运行我发现没有表已被删除(我证实,有一对夫妇十几桌,包括一个开始前命名MIDBLOG)。我在SQL Developer调试模式下运行它,并且执行甚至从未进入循环内部,因为它似乎认为它没有要处理的行,但我确定select语句会返回几十个表名。
接下来我将它修改为这样:
Begin
For T In (SELECT TABLE_NAME FROM all_tables WHERE OWNER = sTarget_DB) Loop
Begin
If T.TABLE_NAME != 'MIDBLOG' THEN
Execute Immediate('Drop Table ' || sTarget_DB || '.' || T.TABLE_NAME);
End If;
Exception
When Others Then
--Don't care if we get an exception here as most likely the table wasn't there to be dropped in the first place.
NULL;
End;
End Loop;
End;
运行此被删除是非常一个我不想删除的唯一表后!更奇怪的是,循环只执行一次,就像select查询只返回一行一样。如果我在SQL Developer 3.2的调试中运行该过程,我可以看到它发生了。我们在SQL Developer的同事电脑上做了同样的事情(可能是3.1),循环只执行一次,但这次它正确地决定不放弃表MIDBLOG,并且再次将所有其他事情放在一边。
如果我运行以上任一例子,如SQL Developer中匿名块它不正是我希望做的事。我尝试了更详细的显式游标声明,并得到与以前相同的结果。我从来没有得到任何例外。
所有这一切都是在Oracle 10g企业版发布10.2.0.4.0(64位)。只要在Oracle 11g企业版版本11.2.0.1.0(64位)上试用过,它就能正常工作。为什么地球上这样一个基本要求在两个版本中表现出如此不同的行为?它可以在两个版本中使用相同的代码工作吗?
关于“其他”异常及其相应的注释,除了表不存在以外,“drop table”命令可能会失败。明确处理-942异常并让其他人正常失败会更好。 –
的确如此,但实际的例外情况对我手边的场景并不感兴趣 - 据我记忆 - 现在是3年半前! –