我正在尝试构建一个将输出放在表格中的查询。 exec(@inloop_query)不知道之前声明的表。 (------------------之间的那部分 这是可能的还是我尝试做一些不起作用的事情? 请指教。
(错误I'是:必须声明表变量" @inloop_table"。严重级15状态2)
DECLARE @frame_db_name VARCHAR(max)
DECLARE @frame_db_id INT
DECLARE @frame_table TABLE (
db_id INT ,
names VARCHAR(max))
DECLARE @frame_count INT
DECLARE @frame_count_max INT
SET @frame_count = 1
SET @frame_count_max = 0
SELECT @frame_count_max = count (name) FROM sys.databases WHERE Name LIKE 'B%' and state_desc = 'online'
INSERT INTO @frame_table SELECT database_id , name FROM sys.databases WHERE Name LIKE 'B%' and state_desc = 'online' ORDER BY database_id
DECLARE @inloop_query VARCHAR(max)
DECLARE @Inloop_table TABLE (
IL_SchemaName VARCHAR(max) ,
IL_TableName VARCHAR(max) ,
IL_IndexName VARCHAR(max) ,
IL_IndexID INT ,
IL_Fragment INT)
IF @frame_count_max <= 0
PRINT '@count_max (<=0) = ' + CAST(@frame_count_max AS VARCHAR)
ELSE
WHILE @frame_count <= @frame_count_max
BEGIN
SELECT @frame_db_name = names , @frame_db_id = db_id FROM @frame_table WHERE db_id IN (SELECT TOP 1 db_id FROM @frame_table ORDER BY db_id)
PRINT '@count_max (>=0) = ' + CAST(@frame_count_max AS VARCHAR)
PRINT '@count = ' + CAST(@frame_count AS VARCHAR(max))
PRINT 'current DB name = ' + CAST(@frame_db_name AS VARCHAR(max))
PRINT 'current DB ID = ' + CAST(@frame_db_id AS VARCHAR(max))
------------------------------------------------------------
SET @inloop_query = '
USE ' + CAST(@frame_db_name AS VARCHAR(max)) +
' INSERT INTO @inloop_table
SELECT SCHEMA_NAME(o.schema_id) AS SchemaName,
OBJECT_NAME(a.object_id) AS TableName,
i.name AS IndexName,
a.index_id AS IndexID,
convert(tinyint,a.avg_fragmentation_in_percent) AS [Fragment]
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL,NULL, ''LIMITED'') AS a
INNER JOIN sys.indexes i ON i.index_id = a.index_id
AND i.object_id = a.object_id
INNER JOIN sys.objects o ON a.object_id = o.object_id
ORDER BY SchemaName, TableName, IndexID'
EXEC(@inloop_query)
------------------------------------------------------------
SET @frame_count = @frame_count + 1
DELETE FROM @frame_table WHERE db_id IN (SELECT TOP 1 db_id FROM @frame_table ORDER BY db_id)
END
答案 0 :(得分:0)
@inloop_table
在@inloop_query之外声明;当后者执行时,它不知道这个变量。如何使用实际的表格?
/* comment this out:
DECLARE @inloop_query VARCHAR(max)
DECLARE @Inloop_table TABLE (
IL_SchemaName VARCHAR(max) ,
IL_TableName VARCHAR(max) ,
IL_IndexName VARCHAR(max) ,
IL_IndexID INT ,
IL_Fragment INT)
*/
-- Create an auxiliary table
CREATE TABLE InLoop_Table (
IL_SchemaName VARCHAR(max) ,
IL_TableName VARCHAR(max) ,
IL_IndexName VARCHAR(max) ,
IL_IndexID INT ,
IL_Fragment INT
);
-- ... And use this table in your dynamic sql:
SET @inloop_query = '
USE ' + CAST(@frame_db_name AS VARCHAR(max)) +
' INSERT INTO InLoop_Table ...
-- Finally, clean up:
DROP TABLE InLoop_Table;
答案 1 :(得分:0)
表变量的范围特定于批处理,因此,由于动态sql作为新批处理执行,因此它不属于范围且无法识别。你当然可以在你的动态sql中声明它,但这是毫无意义的,因为你以后无法访问它。你有两个不错的选择:
您可以将插入放在sql之外,例如
DECLARE @inloop_query NVARCHAR(MAX) = 'USE Master; SELECT 1, 2, 3;';
DECLARE @inloop_table TABLE (A INT, B INT, C INT);
INSERT @inloop_table
EXEC(@inloop_query);
SELECT * FROM @inloop_table;
或者您可以使用临时表,而不是表变量。临时表具有会话范围,因此仍然可以使用EXEC()
识别:
CREATE TABLE #inloop_table (A INT, B INT, C INT);
DECLARE @inloop_query NVARCHAR(MAX) = 'USE Master; INSERT #inloop_table SELECT 1, 2, 3;';
EXEC(@inloop_query);
SELECT * FROM #inloop_table;
我还建议使用正确声明的游标而不是迭代表变量的WHILE
循环。这里的关键方面是正确定义。通常人们只使用DECLARE .. CURSOR FOR SELECT..
并且默认选项比你告诉光标你不会进行更新,不会向后移动等等更慢,更耗费内存。
DECLARE DBCursor CURSOR LOCAL STATIC FORWARD_ONLY READ_ONLY
FOR
SELECT database_id , name
FROM sys.databases
WHERE Name LIKE 'B%' and state_desc = 'online'
ORDER BY database_id;
OPEN DBCursor;
FETCH NEXT FROM DBCursor INTO @frame_db_id, @frame_db_name;
WHILE @@FETCH_STATUS = 0
BEGIN
-- DO WHATEVER YOU NEED WITH EACH DB
FETCH NEXT FROM DBCursor INTO @frame_db_id, @frame_db_name;
END
CLOSE DBCursor;
DEALLOCATE DBCursor;
最后一条评论是,我始终sp_executesql
优先于EXEC()
和this article pretty much covers why,在这种情况下,它并没有太大的区别,但值得注意。< / p>