Sql-Server

在視圖名稱為變數的過程中查詢視圖

  • August 17, 2017

我的問題:我有一組要動態查詢的視圖。我想將視圖名稱載入**SELECT * from sys.all_views**到游標中(我們稱之為view_cursor),然後在過程中執行以下操作:

-- loop starts
FETCH NEXT FROM view_cursor INTO @view_name;
SELECT * FROM @view_name;
-- fetch next
-- loop ends

我已經用一個視圖嘗試了這一點,我只將它作為參數傳遞給儲存過程:

CREATE PROCEDURE [dbo].[query_Special_View](@view_name VARCHAR(100)) AS
DECLARE viewname VARCHAR(100);
DECLARE @counter INT = 0;
BEGIN

   PRINT @view_name
   EXECUTE('SELECT COUNT(Value) INTO' + @counter + 'FROM' + @view_name + '');

   PRINT @counter;
END

然後,我想使用現有視圖名稱執行該過程:

EXEC    [dbo].[query_Special_View]
       @view_name = N'A_very_special_LOC_view' -- the view name as parameter
GO

結果是:

消息 207,級別 16,狀態 1,第 1 行無效的列名稱“值”。

但是,我嘗試COUNT()在過程中呼叫函式的列 Value 確實存在。

那麼,如何在儲存過程中編寫這樣的動態查詢呢?我希望我可以在沒有任何醜陋的動態 SQL 魔法的情況下做到這一點,否則我將使用 Java + JDBC 編寫我的動態查詢邏輯,在其中我可以毫不費力地做這些事情。

問題與您@counter在動態 SQL 中的使用有關。這在幾個方面是錯誤的:您想分配給該變數,但在您使用它的地方,它被轉換為建構作為 SQL 語句的字元串。您應該改為使用sp_executesql計數值並將其作為返回參數傳回。

我還建議您QUOTENAME在語句中使用來防止 SQL 注入。如果有人使用精心構造的名稱創建視圖,他們可能會讓您度過非常糟糕的一天。

嘗試使用此過程定義:

ALTER PROCEDURE [dbo].[query_Special_View](@schema_name sysname, @view_name sysname) AS
BEGIN
    DECLARE @params nvarchar(1000);
    DECLARE @sql nvarchar(1000);
    DECLARE @return bigint;

    SET @params =  N'@count bigint OUT';
    SET @sql = 'SELECT @count = COUNT(*)  FROM ' + QUOTENAME(@schema_name) + '.' + QUOTENAME(@view_name) + ';';

    PRINT @sql

    EXEC sp_executesql @sql, @params, @count = @return OUT

    SELECT SchemaName     = @schema_name,
           ObjectName     = @view_name,
           ObjectRowCount = @return

END
GO

對單個呼叫進行測試就可以了:

EXEC dbo.query_Special_View @schema_name = 'sys', @view_name = 'databases';

回到你原來的問題…

您有一系列要獲取行數的視圖。您甚至不需要將其作為儲存過程。您可以簡單地將那幾行程式碼直接放入游標中並直接執行。

DECLARE @SchemaName sysname,
        @ObjectName sysname,
        @params nvarchar(1000),
        @sql nvarchar(1000),
        @return bigint;

--Table to hold the results 
CREATE TABLE #Results (
    SchemaName sysname,
    ObjectName sysname,
    ObjectRowCount bigint);

--What objects do you want to get the row counts for?
--I'm just querying sys.views, but edit this query for whatever you need
DECLARE obj_cur CURSOR FOR
    SELECT SchemaName = schema_name(schema_id), 
           ObjectName = name
    FROM sys.views v;

--Use that cursor to loop through all objects
OPEN obj_cur;
FETCH NEXT FROM obj_cur INTO @SchemaName, @ObjectName;
WHILE @@FETCH_STATUS = 0
BEGIN
    --Dynamic SQL to get the row count
    SET @params =  N'@count bigint OUT';
    SET @sql = 'SELECT @count = COUNT(*)  FROM ' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@ObjectName) + ';';
    EXEC sp_executesql @sql, @params, @count = @return OUT
    --Put that number into a table
    INSERT INTO #Results (SchemaName, ObjectName, ObjectRowCount)
    SELECT SchemaName = @SchemaName,
           ObjectName = @ObjectName,
           ObjectRowCount   = @return
    FETCH NEXT FROM obj_cur INTO @SchemaName, @ObjectName;
END
CLOSE obj_cur;
DEALLOCATE obj_cur;

SELECT *
FROM #Results;

DROP TABLE #Results;

引用自:https://dba.stackexchange.com/questions/183661