2

我们的应用程序使用一系列表,其中包含许多 varchar(1000) 列。在系统开发过程中,这被认为是足够用户输入文本的空间。但是,现在我们遇到了文本被截断的问题,因此似乎有些用户正在输入更多可以容纳的文本。但是,我相信这些字段的滥用非常猖獗,我想看看正在使用哪些列。

从这里回答的另一个问题中,我提出了以下查询来提取表中 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 专家都可以提供帮助吗?

4

2 回答 2

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
于 2012-10-26T17:33:31.283 回答
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
于 2012-10-26T21:32:17.560 回答