【问题标题】:SQL Server loop through dynamic querySQL Server 循环遍历动态查询
【发布时间】:2018-05-10 08:40:42
【问题描述】:

我有一个过程,我将临时表名作为参数传递。对于里面的每个数据集,我需要获取行数。如何做到这一点?

我需要类似的东西:

CREATE PROCEDURE sp_processing 
  @temp_table_name varchar(50)
AS
  DECLARE @log varchar(max)

/* get list of keys inside temp_table_name */
/* just a pseudo-code example */
SET @l_cursor = CURSOR FOR 
SELECT Key1, Key2, Key3, count(*) 
  FROM @temp_table_name -- table name passed as text 
 GROUP by Key1, Key2, Key3;

WHILE "there are results"
BEGIN
  @log += @Key1 +', '+ @Key2 +', '+ @Key3 +', '+ @count + CHAR(13)+CHAR(10);
END

UPDATE log_table SET log_column = @log WHERE....;

END /* procedure */

有没有办法循环这个?

我知道我可以选择将结果提取到 table 类型和 THEN 循环,但这需要使用表类型,所以想知道如果没有表变量这是否可以实现。

编辑:我只需要打印每组键的计数。

【问题讨论】:

  • 我不太明白您要做什么。如果您收到临时表名称作为参数,那么您必须通过动态 SQL 访问它。为什么你需要一个光标呢?为什么需要循环?
  • 其实你是对的,我不需要循环,因为我只需要在varchar 变量中打印计数,但我想我需要遍历记录:-(
  • 在问题中包含您的完整用例,这样我们就可以避免问答乒乓。
  • 我发现这个解决方案非常简洁:*.com/questions/8005846/…

标签: sql-server loops tsql dynamic-sql dynamicquery


【解决方案1】:

这对我有用:

DECLARE @l_sql nvarchar(max)
DECLARE @temp_table_name varchar(50) = 'SOME_TABLE'
DECLARE @combinedString varchar(max)
SET @l_sql = 'SELECT @combinedString = COALESCE(@combinedString, '''') + convert(varchar,[Key1]) +'', ''+ convert(varchar,[Key3]) +'': ''+ convert(varchar,COUNT(*)) + ''| '' + CHAR(13)+CHAR(10) '
           + '  FROM ' + @temp_table_name  
           + ' GROUP BY [Key1], [Key3]'
           + ' ORDER BY [Key1], [Key3]';

EXECUTE sp_executesql @l_sql, N'@combinedString varchar(max) OUTPUT', @combinedString = @combinedString OUTPUT ;

SELECT @combinedString 

结果:

1, 1: 4| 
1, 2: 2| 
1, 3: 1| 
2, 5: 1| 

【讨论】:

    【解决方案2】:

    您应该始终尽量避免循环和光标。这是针对您的案例的基于集合的解决方案。请查看(特别是更新过滤器),看看它是否适合您的需求。

    CREATE PROCEDURE sp_processing 
      @temp_table_name varchar(50)
    AS
    BEGIN
    
        DECLARE @DynamicSQL VARCHAR(MAX) = '
    
            ;WITH LogRecords AS
            (
                SELECT
                    LogRecord = 
                        ISNULL(T.Key1, '''') + '','' + 
                        ISNULL(T.Key2, '''') + '','' +  
                        ISNULL(T.Key2, '''') + '','' + 
                        CONVERT(VARCHAR(20), COUNT(1))
                FROM
                    QUOTENAME(''' + @temp_table_name + ''') AS T
                GROUP BY
                    T.Key1,
                    T.Key2,
                    T.Key3
            )
            UPDATE L SET
                log_column = STUFF(
                    (
                        SELECT
                            R.LogRecord + CHAR(13) + CHAR(10)
                        FROM
                            LogRecords AS R
                        FOR XML
                            PATH('')
                    ),
                    1, 1, '')
            FROM
                log_table AS L
            WHERE
                L.IdFilter = 999999999'
    
        PRINT @DynamicSQL
    
        -- EXEC (@DynamicSQL)
    
    END
    

    【讨论】:

    • 感谢您的努力。你觉得这个答案怎么样,我觉得很简洁:*.com/questions/8005846/…
    • 第一个答案有 2 个解决方案。第一个仅在过滤特定集合时有效(不适用于 group by),第二个与我在这里写的类似。但是,只要通过参数接收表名,就无法使用 Dynamic SQL 进行转义。