动态SQL:EXECUTE-Statment中的字符串截断

时间:2017-09-28 14:45:20

标签: sql-server

我想监视SQL Server实例中任何数据库的大小,所以我想出了这个构建临时表的查询,它提供了我想要的东西

/*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命令更改数据库时上下文的更改有关。但我也尝试了数据类型nvarchartextntext(对局部变量无效),charnchar以及{{1这是sys.databases的“name”字段的字段类型。 关于如何阻止这种行为的任何建议?

2 个答案:

答案 0 :(得分:2)

尝试转义数据库名称:

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

答案 1 :(得分:0)

以下是如何在不使用游标的情况下执行此操作的快速示例。它仍然需要动态sql但没有游标。 :)我意识到你正在使用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