【问题标题】:Looping through column names with dynamic SQL使用动态 SQL 循环遍历列名
【发布时间】:2013-12-26 03:12:49
【问题描述】:

我刚刚想出了一个想法,用一段代码来显示每列的所有不同值,并计算每列有多少条记录。我希望代码遍历所有列。

这是我到目前为止所拥有的...我是 SQL 新手,所以请耐心等待:)

硬编码:

  select [Sales Manager], count(*)
  from  [BT].[dbo].[test]
  group by [Sales Manager]
  order by 2 desc

尝试动态 SQL:

Declare @sql varchar(max),
@column as varchar(255)

    set @column = '[Sales Manager]'
    set @sql = 'select ' + @column + ',count(*) from [BT].[dbo].[test] group by ' + @column + 'order by 2 desc'

    exec (@sql)

这两个都可以正常工作。我怎样才能让它遍历所有列?我不介意我是否必须对列名进行硬编码,并且它通过在每个列中为@column 替换来工作。

这有意义吗?

谢谢大家!

【问题讨论】:

    标签: sql loops dynamic


    【解决方案1】:

    您可以使用动态 SQL 并获取表的所有列名。然后构建脚本:

    Declare @sql varchar(max) = ''
    declare @tablename as varchar(255) = 'test'
    
    select @sql = @sql + 'select [' + c.name + '],count(*) as ''' + c.name +  ''' from [' + t.name + '] group by [' + c.name + '] order by 2 desc; ' 
    from sys.columns c
    inner join sys.tables t on c.object_id = t.object_id
    where t.name = @tablename
    
    EXEC (@sql)
    

    @tablename 更改为您的表名称(不包括数据库或架构名称)。

    【讨论】:

    • 我试过这段代码...它似乎运行了,但我应该添加一些东西吗?我没有看到那里有一个循环?干杯,
    • 你不需要循环,所有列的所有查询都在@sql变量中。
    • 嘿Szymon。好吧,我想我明白了……哈哈。我得到“命令成功完成”,但没有显示结果...我必须将代码的哪一部分更改为我自己的值?
    • 将@tablename 更改为您的表的名称(不包括数据库或架构名称)。
    • 对了。所以完全复制你的代码......不幸的是没有发生任何事情。 :( 结果应该显示在结果窗口中吧?
    【解决方案2】:

    这是一个 XY 答案,但如果您不介意对列名进行硬编码,我建议您这样做,并完全避免动态 SQL 和循环。动态 SQL 通常被认为是最后的手段,如果不小心,您将面临安全问题(SQL 注入攻击),如果无法缓存查询和执行计划,通常会变慢。

    如果您有大量列名,您可以在 Word 中编写一段快速代码或邮件合并来为您进行替换。


    但是,至于如何获取列名,假设这是 SQL Server,您可以使用以下查询:

    SELECT c.name
    FROM sys.columns c
    WHERE c.object_id = OBJECT_ID('dbo.test')
    

    因此,您可以从此查询构建动态 SQL:

    SELECT 'select ' 
        + QUOTENAME(c.name) 
        + ',count(*) from [BT].[dbo].[test] group by ' 
        + QUOTENAME(c.name)  
        + 'order by 2 desc'
    FROM sys.columns c
    WHERE c.object_id = OBJECT_ID('dbo.test')
    

    并使用光标循环。

    或者将整个东西编译成一批并执行。这里我们使用FOR XML PATH('')技巧:

    DECLARE @sql VARCHAR(MAX) = (
        SELECT ' select ' --note the extra space at the beginning
            + QUOTENAME(c.name) 
            + ',count(*) from [BT].[dbo].[test] group by ' 
            + QUOTENAME(c.name)  
            + 'order by 2 desc'
        FROM sys.columns c
        WHERE c.object_id = OBJECT_ID('dbo.test')
        FOR XML PATH('')
    )
    
    EXEC(@sql)
    

    注意我使用the built-in QUOTENAME function 来转义需要转义的列名。

    【讨论】:

      【解决方案3】:

      您想知道表的所有列中不同的列值吗?只需在以下代码中将表名 Employee 替换为您的表名:

      declare @SQL nvarchar(max)
      set @SQL = ''
      ;with cols as (
      select Table_Schema, Table_Name, Column_Name, Row_Number() over(partition by Table_Schema, Table_Name
      order by ORDINAL_POSITION) as RowNum
      from INFORMATION_SCHEMA.COLUMNS
      )
      
      select @SQL = @SQL + case when RowNum = 1 then '' else ' union all ' end
      + ' select ''' + Column_Name + ''' as Column_Name, count(distinct ' + quotename (Column_Name) + ' ) As DistinctCountValue, 
      count( '+ quotename (Column_Name) + ') as CountValue FROM ' + quotename (Table_Schema) + '.' + quotename (Table_Name)
      from cols
      where Table_Name = 'Employee' --print @SQL
      
      execute (@SQL)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-16
        • 2020-03-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-07
        相关资源
        最近更新 更多