2

このアプリケーションでは、多くの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 }}**

もちろん、最初のクエリは列の名前を返しますが、2番目のクエリは列への参照を必要とするため、それらを適切に組み合わせる方法がわかりません。SQL Serverの達人が助けてくれますか?

4

2 に答える 2

4

2つの派生テーブルを結合するか、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 に答える