Sql server 动态SQL:执行语句中的字符串截断

Sql server 动态SQL:执行语句中的字符串截断,sql-server,Sql Server,我想监控SQLServer实例中任何数据库的大小,所以我提出了这个查询,它构建了一个临时表,提供了我想要的内容 /*DROP TEMP TABLE IF STILL EXISTENT*/ IF OBJECT_ID('tempdb..#sizes') IS NOT NULL DROP TABLE #sizes; /*DECLARE CURSOR curs1 to query the names of all relevant databases*/ DECLARE curs1 INSENSITIV

我想监控SQLServer实例中任何数据库的大小,所以我提出了这个查询,它构建了一个临时表,提供了我想要的内容

/*DROP TEMP TABLE IF STILL EXISTENT*/
IF OBJECT_ID('tempdb..#sizes') IS NOT NULL
DROP TABLE #sizes;
/*DECLARE CURSOR curs1 to query the names of all relevant databases*/
DECLARE curs1 INSENSITIVE CURSOR FOR
select CAST(name AS varchar(MAX)) from sys.databases WHERE state_desc ='ONLINE' AND name NOT IN ('tempdb', 'master', 'model', 'msdb', 'sysdb', 'tempdb2')
/*Open Cursor*/
OPEN curs1
/*Declare Variable to hold the value of current db*/
declare @dbname varchar(MAX) = 'dummy'
/*Create the temporary table for results*/
CREATE TABLE #sizes (DBname varchar(MAX), physicalname varchar(MAX), TotalSizeMB INT, AvailableSpaceMB INT)
/*Query the datafile statistics for every database dynamically*/
WHILE(1=1)
BEGIN
FETCH NEXT FROM curs1 INTO @dbname
IF @@FETCH_STATUS != 0
BREAK;
EXECUTE('USE ' + @dbname + ';INSERT INTO #sizes
SELECT DB_NAME(), f.physical_name,
CAST((f.size/128.0) AS DECIMAL(15,2)), 
CAST(f.size/128.0 - CAST(FILEPROPERTY(f.name, ''SpaceUsed'') AS int)/128.0 AS DECIMAL(15,2))
FROM sys.database_files f;')
END
Select * from #sizes
/*Cleanup*/
DROP TABLE #sizes

CLOSE curs1
DEALLOCATE curs1
当光标获取包含“-”的字符串时,它会在该点拆分该字符串,留下一个不完整的数据库名称,但找不到该名称。我将
EXECUTE
函数隔离为问题所在。我假设这与使用
use
命令更改数据库时上下文的更改有关。但是我也尝试了数据类型
nvarchar
text
ntext
(对局部变量无效),
char
nchar
以及
sysname
,这是sys.databases的“name”列的字段类型。
有关于如何停止此行为的建议吗?

尝试转义数据库名称:

'USE [' + @dbname + ']; ...

尝试转义数据库名称:

'USE [' + @dbname + ']; ...

下面是一个快速示例,说明如何在不使用光标的情况下执行此操作。它仍然需要动态sql,但不需要游标。:)我知道您使用的是FILEPROPERTY,这里的FILEPROPERTY将为NULL,但我很快就把这个示例放到了一起。因为我怀疑你可能会继续使用你已经拥有的游标版本,所以我没有重构那部分

declare @SQL nvarchar(max) = ''

select @SQL = @SQL + 
'SELECT DatabaseName = ''' + name + ''', f.physical_name collate SQL_Latin1_General_CP1_CI_AS,
CAST((f.size/128.0) AS DECIMAL(15,2)), 
CAST(f.size/128.0 - CAST(FILEPROPERTY(f.name, ''SpaceUsed'') AS int)/128.0 AS DECIMAL(15,2))
FROM [' + name + '].sys.database_files f union all '
from sys.databases 
WHERE state_desc ='ONLINE' 
    AND name NOT IN ('tempdb', 'master', 'model', 'msdb', 'sysdb', 'tempdb2')

select @SQL = left(@SQL, len(@SQL) - 10)

select @SQL
--Uncomment the next line when you are comfortable the dynamic sql will work
--exec sp_executesql @SQL

下面是一个快速示例,说明如何在不使用光标的情况下执行此操作。它仍然需要动态sql,但不需要游标。:)我知道您使用的是FILEPROPERTY,这里的FILEPROPERTY将为NULL,但我很快就把这个示例放到了一起。因为我怀疑你可能会继续使用你已经拥有的游标版本,所以我没有重构那部分

declare @SQL nvarchar(max) = ''

select @SQL = @SQL + 
'SELECT DatabaseName = ''' + name + ''', f.physical_name collate SQL_Latin1_General_CP1_CI_AS,
CAST((f.size/128.0) AS DECIMAL(15,2)), 
CAST(f.size/128.0 - CAST(FILEPROPERTY(f.name, ''SpaceUsed'') AS int)/128.0 AS DECIMAL(15,2))
FROM [' + name + '].sys.database_files f union all '
from sys.databases 
WHERE state_desc ='ONLINE' 
    AND name NOT IN ('tempdb', 'master', 'model', 'msdb', 'sysdb', 'tempdb2')

select @SQL = left(@SQL, len(@SQL) - 10)

select @SQL
--Uncomment the next line when you are comfortable the dynamic sql will work
--exec sp_executesql @SQL

这里不需要光标。我真的不喜欢游标,即使对于这样的管理任务也是如此。我将很快发布一个更简单的方法,这里不需要光标。我真的不喜欢游标,即使对于这样的管理任务也是如此。我很快就会发布一个更简单的方法。谢谢!这很有趣。尤其是因为在php5中获取解决方案的结果时遇到困难。比游标简单得多。:)请详细说明为什么FILEPROPERTY表达式会导致空值?filename参数需要nchar(128)数据,但即使在我使用CAST时,它也不起作用。FILEPROPERTY是一个与其当前执行的数据库相关的函数。在我放在这里的代码中,整个过程都是针对一个数据库运行的。因此,FILEPROPERTY将返回NULL,因为当前数据库中不存在该文件。仔细看,您会发现它只返回您运行此操作的数据库的值。谢谢!这很有趣。尤其是因为在php5中获取解决方案的结果时遇到困难。比游标简单得多。:)请详细说明为什么FILEPROPERTY表达式会导致空值?filename参数需要nchar(128)数据,但即使在我使用CAST时,它也不起作用。FILEPROPERTY是一个与其当前执行的数据库相关的函数。在我放在这里的代码中,整个过程都是针对一个数据库运行的。因此,FILEPROPERTY将返回NULL,因为当前数据库中不存在该文件。仔细观察,您会发现它只返回运行此操作的数据库的值。