2017-03-06 30 views
-1

我試圖建立一個查詢,把他的輸出放在一個表中。 exec(@inloop_query)不知道以前的聲明表。 (在------------------ 之間的部分是可能的,或者我要嘗試做一些事情,不工作? 請告知。T-SQL查詢出錯exec不在表

(我有錯誤是:必須聲明表變量「@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

@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; 
+0

感謝您的支持。 我也想到了這一點,但問題是我不能在我正在處理的數據庫上創建任何表格。 另外我已經嘗試過(並且確實有效)在@inloop_query中創建TABLE,但是我需要在另一次輸出。 我真的希望有一種方法可以使這個工作。 – hexedecimal

+0

那麼GarethD的解決方案呢? –

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; 

最後一個評論,是我總是在EXEC()this article pretty much covers why上使用sp_executesql,在這種情況下它沒有太大的區別,但值得注意。

+0

其實我們可以訪問**一個在動態sql中聲明的變量,如果我們使用'sp_executesql',但它有點涉及:http://stackoverflow.com/a/42528011/1465748 –

+0

@GiorgosAltanis那不適用於表格變量,您只能輸出標量變量。因此,您需要序列化結果,並將其作爲標量變量返回,XML將成爲明顯的候選者,那麼您需要將XML反序列化回表中,以便對結果進行任何操作。所以是的,這是可能的,但它是非常努力的,它可能永遠不會比使用臨時表更好的選擇。 – GarethD

+0

感謝有關表變量的澄清,我確實認爲這是一個困難的方法。 –