我发现了一个关于如何使用光标的很棒的example:
DECLARE @DB_Name varchar(100)
DECLARE @Command nvarchar(200)
DECLARE database_cursor CURSOR FOR
SELECT name
FROM MASTER.sys.sysdatabases
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO @DB_Name
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @Command = 'SELECT ' + '''' + @DB_Name + '''' + ', SF.filename, SF.size FROM sys.sysfiles SF'
EXEC sp_executesql @Command
FETCH NEXT FROM database_cursor INTO @DB_Name
END
CLOSE database_cursor
DEALLOCATE database_cursor
问题是,当我执行它时,它总是返回相同的filename
和size
。
那么让我们把它放回去:
DECLARE @DB_Name varchar(100)
DECLARE @Command nvarchar(200)
DECLARE database_cursor CURSOR FOR
SELECT name
FROM MASTER.sys.sysdatabases
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO @DB_Name
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @Command = ' USE ? SELECT ' + '''' + @DB_Name + '''' + ', SF.filename, SF.size FROM sys.sysfiles SF'
EXEC sp_executesql @Command
FETCH NEXT FROM database_cursor INTO @DB_Name
END
CLOSE database_cursor
DEALLOCATE database_cursor
但SQL Server对每个数据库都抛出此错误:
消息102,级别15,状态1,行1
'?'附近有语法错误
正好是我数据库数量的5倍。
如何使用此光标?
2条答案
按热度按时间guicsvcw1#
您需要使用@DB_Name变量,而不是
?
:fcwjkofz2#
如果有人能够在此系统上创建数据库,他们可能会以测试、QA为幌子,或者通过允许用户创建数据库的UI,创建名为
tempdb; SELECT name,salary FROM Accounting.dbo.Employees;
的数据库,从而获得对敏感信息的访问权限(或者,更糟的是,造成破坏!),而这条路径只能通过动态SQL的执行上下文来实现。此外,您不应该使用过时的兼容性视图,如
sysdatabases
和sysfiles
,并且您应该保护自己不受脱机数据库和其他不可访问数据库的影响,这些数据库将导致您的进程暂停。(考虑到数据库名称可能更长),应始终为nvarchar
,因为人们可以将其数据库命名为🐳
或[🐻🐻🐻🐻🐻]
等。最后,您需要避免使用默认游标所导致的问题,这可能导致数据库被任意跳过。这已经被我在评论(
sp_ineachdb
)中提到的过程和Bertrand先生写的in the referenced article的背景所解决。如果您真的不想使用一个开源过程,它已经完成了您所需要的所有事情,并保护您免受许多您可能还不知道的问题的影响,那么请尝试:
如果您希望它们都在同一个数据集中返回,而不是每个数据库只有一个数据集,您可以:
但是实际上,您可以使用
sp_ineachdb
。安装了该过程后,您的代码将立即变得如此简单: