2017-03-06 11 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

あなたの喜んでいただきありがとうございます。 私もそれについて考えましたが、問題は私が作業しているDB上にテーブルを作ることができないということです。 また、@inloop_queryの内部にTABLEを作成しようとしましたが、別の時に出力が必要でした。 私は本当にこれを動作させる方法があることを願っています。 – hexedecimal

+0

GarethDのソリューションはどうですか? –

0

テーブル変数の有効範囲はバッチに固有です。したがって、動的SQLは新しいバッチとして実行されるため、有効範囲外になり、認識されません。もちろん、動的SQL内で宣言することもできますが、後でアクセスできないため、それはかなり無意味です。あなたは2つの適切な選択肢があります:

あなたは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 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; 

ワンなど、最終的なコメントを人々はちょうどDECLARE .. CURSOR FOR SELECT..を使用して、デフォルトのオプションは、はるかに遅いとより多くのメモリを消費しています私がいつもsp_executesqlEXEC()this article pretty much covers whyに当てはめているのですが、この例ではそれほど大きな違いはありませんが、それは注目に値します。

+0

実際には、** sp_executesqlを使用するとダイナミックSQL内で宣言された変数に**アクセスできますが、それは多少関わっています:http://stackoverflow.com/a/42528011/1465748 –

+0

@GiorgosAltanisテーブル変数に適用すると、スカラ変数のみを出力できます。したがって、結果をシリアライズしてスカラー変数として返す必要があり、XMLが明白な候補になる場合は、XMLを逆シリアル化して結果に何かを実行する必要があります。そうです、それは可能ですが、おそらく一時テーブルを使用するよりも良い選択肢ではないでしょう。 – GarethD

+0

テーブル変数についての説明をお寄せいただき、ありがとうございます。 –

関連する問題