SQL Server - 在聚合函数中按名称引用列

时间:2012-10-26 17:20:44

标签: sql-server sql-server-2008 sql-server-2008-r2

我们的应用程序使用一系列包含许多varchar(1000)列的表。在系统开发期间,这被认为是用户输入文本的足够空间。但是,现在我们遇到了文本被切断的问题,所以看起来有些用户正在输入更多可以容纳的文本。但是,我认为这些字段的滥用行为猖獗,我想看看哪些列正在使用。

从SO上回答的另一个问题,我提出了以下查询来提取表中varchar列的名称:

select
   syscolumns.name as [Column],
   syscolumns.length as [MaxLength]
from 
   sysobjects, syscolumns 
where sysobjects.id = syscolumns.id
and   sysobjects.xtype = 'u'
and   sysobjects.name = 'TableWithTooManyVarcharColumns'
and syscolumns.xusertype = 167

但现在我想在新查询中使用这些列的名称,并计算

SELECT 
[Column] as [Name],
[MaxLength],
MAX(LEN([Column])) as [MaxUsedLength],
AVG(LEN([Column])) as [AvgUsedLength],
STDEV(LEN([Column])) as [StdDev]
FROM TableWithTooManyVarcharColumns
INNER JOIN **{{ reference to table from query above }}**

当然,第一个查询返回列的名称,而第二个查询需要对列的引用,所以我不确定如何正确组合它们。任何SQL Server大师都能提供帮助吗?

2 个答案:

答案 0 :(得分:4)

连接两个派生表或使用CTE。顺便说一下,您正在为模式引用使用一些过时的术语

select 
      DefinedName = sysdef.name,
      Columnname = tbl.name,
      DefinedLength = sysdef.max_length, 
      etc ...
from (
        select c.name, c.max_length
            from sys.columns c 
        join sys.tables t 
            on c.object_id = t.object_id
            where t.name = 'TableWithTooManyVarcharColumns'
) sysdef
join (
        SELECT 
                [Column] as [Name],
                [MaxLength],
                MAX(LEN([Column])) as [MaxUsedLength],
                AVG(LEN([Column])) as [AvgUsedLength],
                STDEV(LEN([Column])) as [StdDev]
        FROM TableWithTooManyVarcharColumns
) tbl
on sysdef.name = tbl.name

;WITH sysdef AS (
        select c.name, c.max_length
                from sys.columns c 
            join sys.tables t 
                on c.object_id = t.object_id
                where t.name = 'TableWithTooManyVarcharColumns'
),
tbl AS (
        SELECT 
                [Column] as [Name],
                [MaxLength],
                MAX(LEN([Column])) as [MaxUsedLength],
                AVG(LEN([Column])) as [AvgUsedLength],
                STDEV(LEN([Column])) as [StdDev]
        FROM TableWithTooManyVarcharColumns
)
select
      DefinedName = sysdef.name,
      Columnname = tbl.name,
      DefinedLength = sysdef.max_length, 
      etc ...
from tbl t 
join sysdef d
on tbl.name = d.name

修改

declare @sql nvarchar(4000)
declare @colname nvarchar(100)
declare @max_length nvarchar(15)
declare c cursor for 
    select c.name, c.max_length
    from sys.columns c 
        join sys.tables t
            on c.object_id = t.object_id
    where t.name = 'TableWithTooManyVarcharColumns'

open c 
fetch next from c into 
    @colname, @max_length

    while @@FETCH_STATUS = 0
        begin
            set @sql = 'SELECT ''' + QUOTENAME(@colname) + ''', ' + @max_length + ' [MaxLength],' +                     
                    'MAX(LEN('+QUOTENAME(@colname)+')) as [MaxUsedLength],
                    AVG(LEN('+QUOTENAME(@colname)+')) as [AvgUsedLength],
                    STDEV(LEN('+QUOTENAME(@colname)+')) as [StdDev]
                    FROM TableWithTooManyVarcharColumns'
            exec(@sql)
            fetch next from c 
                into @colname, @max_length
        end
    close c 
    deallocate c

答案 1 :(得分:2)

为了完整起见,我将添加原来是我的解决方案。这是swasheck的解决方案的模式,所以他得到了他的答案,并且这个解决方案有点混乱,但它应该作为任何其他可能遇到这个问题的人的基础:

DECLARE @TableName nvarchar(100) = 'TableToAnalyze' -- Change to your table name

declare @SQLStat nvarchar(4000)
declare @ColName nvarchar(100)
declare @MaxLength integer
declare @MaxUsedLength integer
declare @AvgUsedLength float
declare @StdDev float
declare @parm1IN nvarchar(100)
declare @parm2IN integer
declare @parm3IN integer
declare @parm4IN float
declare @parm5IN float
declare @parm1O integer
declare @parm2O float
declare @parm3O float

CREATE TABLE #Details (
    ColumnName nvarchar(100) NULL,
    MaxLength integer null,
    MaxUsedLength integer null,
    AvgUsedLength float null,
    StdDev float null
)

declare c cursor for 
    select c.name, c.max_length
    from sys.columns c 
        join sys.tables t
            on c.object_id = t.object_id
    where t.name = @TableName
    and c.user_type_id = 167

DECLARE @ParmDefinition1 NVARCHAR(500)

SET @ParmDefinition1 = N'@parm1IN nvarchar(100), 
                         @parm1O int OUTPUT, 
                         @parm2O float OUTPUT, 
                         @parm3O float OUTPUT'

DECLARE @ParmDefinition2 NVARCHAR(500)

SET @ParmDefinition2 = N'@parm1IN nvarchar(100), 
                         @parm2IN int, 
                         @parm3IN int, 
                         @parm4IN float, 
                         @parm5IN float'

open c 
fetch next from c into 
    @ColName, @MaxLength

    while @@FETCH_STATUS = 0
        begin
            set @SQLStat = N'SELECT @parm1O = MAX(LEN('+ QUOTENAME(@ColName) + ')),
                    @parm2O = AVG(LEN('+ QUOTENAME(@ColName) + ')),
                    @parm3O = STDEV(LEN('+ QUOTENAME(@ColName) + '))
                    FROM ' + QUOTENAME(@TableName)

            EXECUTE sp_executesql @SQLStat, @ParmDefinition1, 
            @parm1IN = @ColName,
            @parm1O = @MaxUsedLength OUTPUT,    
            @parm2O = @AvgUsedLength OUTPUT,
          @parm3O = @StdDev OUTPUT


            set @SQLStat = 'INSERT INTO #Details (  ColumnName, MaxLength, MaxUsedLength, AvgUsedLength, StdDev)'
            + ' VALUES(@parm1IN, @parm2IN, @parm3IN, @parm4IN, @parm5IN)'

            EXECUTE sp_executesql @SQLStat, @ParmDefinition2,
            @parm1IN = @ColName,
            @parm2IN = @MaxLength,
            @parm3IN = @MaxUsedLength,  
            @parm4IN = @AvgUsedLength,
          @parm5IN = @StdDev

            fetch next from c 
                into @ColName, @MaxLength
        end
    close c 
    deallocate c

SELECT * FROM #Details

DROP TABLE #Details