在视图名称为变量的过程中查询视图

Bru*_*tig 2 sql-server stored-procedures ssms view sql-server-2016

我的问题:我有一组视图,我想从中动态查询。我想将视图名称加载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
Run Code Online (Sandbox Code Playgroud)

我已经在一个视图中尝试过这个,我将它作为参数传递给存储过程:

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
Run Code Online (Sandbox Code Playgroud)

然后,我想使用现有视图名称执行该过程:

EXEC    [dbo].[query_Special_View]
        @view_name = N'A_very_special_LOC_view' -- the view name as parameter
GO
Run Code Online (Sandbox Code Playgroud)

结果是:

消息 207,级别 16,状态 1,第 1 行 列名“值”无效。

但是,我尝试COUNT()在过程中调用该函数的列 Value确实存在。

那么,如何在存储过程中编写这样的动态查询呢?我希望我可以在没有任何丑陋的动态 SQL 魔法的情况下做到这一点,否则我将使用 Java + JDBC 编写我的动态查询逻辑,我可以在其中轻松完成这些事情。

AMt*_*two 5

问题与您@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
Run Code Online (Sandbox Code Playgroud)

对单个调用进行测试就可以正常工作:

 EXEC dbo.query_Special_View @schema_name = 'sys', @view_name = 'databases';
Run Code Online (Sandbox Code Playgroud)


回到你原来的问题......

您有一系列想要获取行计数的视图。您甚至不需要将其作为存储过程。您可以简单地将这几行代码直接放入游标中并直接执行。

 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;
Run Code Online (Sandbox Code Playgroud)