在尝试再次打开游标之前,如果游标已存在,如何确保将其释放?
对于表,我可以使用类似的东西:
if exists (select top 1 from tempdb.sys.tables where name = '##tmpTable')
drop table ##tmpTable;
... then I can recreate my ##tmpTable
但我无法弄清楚如何为光标执行此操作,就像
-- First clean up if already exists..
..... <----- what goes here???
-- Declare and use a cursor
DECLARE someCursorName CURSOR
FOR
select something from somewhere
FOR READ ONLY
我这样做是为了确保我的脚本在开始工作之前清理干净
我能想到的最好的是:
begin try DEALLOCATE someCursorName ; end try begin catch end catch
是这样的一个好的做法?
编辑:
这是维护脚本。在我们大量客户定制的数据库中,可能有许多表,游标用于跨表运行统计分析 - 根据表的类型,会发生不同的情况。基本上有很多动态sql。如果脚本失败,我希望能够重复该工作,而不必担心手动干预。这里只有一层范围。
像所有事情一样,我很高兴用设置操作替换光标。这些是游标循环所做的事情:
- 构造sql来重组/重建索引(最初有手动sql来确定要运行的DDL,然后发出DDL)
- 分析数据分布和错误不同的表
- 在日志中查找错误并查找适当的表并获取该数据(最初有手动sql来确定错误所在的位置,然后剪切并粘贴模板以根据错误类型查找错误)
How can I make sure that I deallocate a cursor if it already exists before I try and open it again?
For a table I can use something like:
if exists (select top 1 from tempdb.sys.tables where name = '##tmpTable')
drop table ##tmpTable;
... then I can recreate my ##tmpTable
But I can't work out how to do it for a cursor like
-- First clean up if already exists..
..... <----- what goes here???
-- Declare and use a cursor
DECLARE someCursorName CURSOR
FOR
select something from somewhere
FOR READ ONLY
I'm doing this to ensure that my script cleans up before it starts work
Best I can come up with is :
begin try DEALLOCATE someCursorName ; end try begin catch end catch
Is this a good practice?
EDIT:
This is maintennance script. In our heavily customer customised databases there can be many tables and the cursor is used to run statistical analyses across the tables - depending on the types of tables different things happen. Basically lots of dynamic sql. If the script fails I'd like to be able to repeat the job without worrying about manual intervention. There is only one level of scope here.
Like all things I'm happy to replace the cursors with set operations. These are the things that the cursors loops do:
- construct sql to reorg/rebuild indexes (orginally there was manual sql to determine the DDL to run, and then the DDL was issued)
- analyse data spreads and errors in different tables
- find errors in logs and look up appropriate tables and grab that data (orginally there was manual sql to determine the places where errors where and then cut and paste template(s) to look up the errors dependant upon types of error)
发布评论
评论(2)
您可以将游标声明为变量,然后当它超出范围时它将自动关闭并释放。下面是将其与动态 SQL 结合使用的示例。
You can declare the Cursor as a variable then it will be closed and deallocated automatically when it goes out of scope. Example of using this in conjunction with dynamic SQL below.
创建
CURSOR
变量,然后使用SET
定义它时,当变量超出范围(即批处理或子流程结束)时,确实会自动释放它,这种构造也是完全没有必要的。假设您没有将游标本身传递到进程的各个嵌套级别,或者需要它在批次之间生存,那么最简单的方法(可能也是最好的总体方法)是将游标声明为
LOCAL
。虽然可以在LOCAL
和GLOBAL
之间配置未指定,但如果未指定,则默认设置为游标为GLOBAL
。在问题的代码中,没有LOCAL
关键字,因此我们可以假设光标是GLOBAL
这就是为什么需要清理先前运行的问题甚至出现的原因向上。因此,只需将LOCAL
关键字添加到游标声明中即可。现在,对于那些您实际上想要一个
GLOBAL
游标并因此需要首先检查以确保它尚未被声明的情况,有两种简单的方法可以对此进行测试:sys.tables
)我还在 SQL Server 2005 SP4 上进行了测试,发现上述所有三项的行为方式也相同。
While creating a
CURSOR
variable and then usingSET
to define it will indeed automatically deallocate it when the variable goes out of scope (i.e. end of the batch or sub-process), that construct is also entirely unnecessary.Assuming that you aren't passing the cursor itself around to various nested levels of the process, or need it to survive between batches, then the simplest approach (and probably best overall) is to declare the cursor as
LOCAL
. While unspecified is configurable betweenLOCAL
andGLOBAL
, the default setting is that cursors areGLOBAL
if not specified. In the code in the question, there is noLOCAL
keyword so we can assume that the cursor isGLOBAL
which is why this issue of needing to clean up a prior run even came up. So, just add theLOCAL
keyword to the cursor declaration.Now, for those cases where you actually want a
GLOBAL
cursor and so need to check first to make sure that it hasn't already been declared, there are two easy ways to test for this:sys.tables
for tables)I also tested on SQL Server 2005, SP4 and found that all three items noted above behaved the same way there as well.