Sql-Server
在視圖名稱為變數的過程中查詢視圖
我的問題:我有一組要動態查詢的視圖。我想將視圖名稱載入**
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;