17

我正在尝试从表中获取所有列的列表,其中包含它们的数据类型、数据长度和该列中最长值的长度。

我有这个 SQL 用于获取列及其数据类型和长度:

SELECT 
    Object_Name(c.object_id),
    c.name 'Column Name',
    t.Name 'Data type',
    c.max_length 'Max Length'
FROM    
    sys.columns c
INNER JOIN 
    sys.types t ON c.system_type_id = t.system_type_id
WHERE
    c.object_id = OBJECT_ID('MyTable')

我有这个 SQL 来获取一个值的最大长度:

SELECT Max(Len(MyColumn))
FROM MyTable

但我不知道如何将它们结合起来。我正在使用 SQL Server 2008。

4

14 回答 14

17

Thanks for the suggestions. I have come up with the following solution. It gets me the data i need but would be interested to see if it can be made more efficient.

declare @results table
(
ID varchar(36),
TableName varchar(250),
ColumnName varchar(250),
DataType varchar(250),
MaxLength varchar(250),
Longest varchar(250),
SQLText varchar(250)
)

INSERT INTO @results(ID,TableName,ColumnName,DataType,MaxLength,Longest,SQLText)
SELECT 
    NEWID(),
    Object_Name(c.object_id),
    c.name,
    t.Name,
    case 
        when t.Name != 'varchar' Then 'NA'
        when c.max_length = -1 then 'Max' 
        else CAST(c.max_length as varchar)
    end,
    'NA',
    'SELECT Max(Len(' + c.name + ')) FROM ' + OBJECT_SCHEMA_NAME(c.object_id) + '.' + Object_Name(c.object_id)
FROM    
    sys.columns c
INNER JOIN 
    sys.types t ON c.system_type_id = t.system_type_id
WHERE
    c.object_id = OBJECT_ID('MyTable')    


DECLARE @id varchar(36)
DECLARE @sql varchar(200)
declare @receiver table(theCount int)

DECLARE length_cursor CURSOR
    FOR SELECT ID, SQLText FROM @results WHERE MaxLength != 'NA'
OPEN length_cursor
FETCH NEXT FROM length_cursor
INTO @id, @sql
WHILE @@FETCH_STATUS = 0
BEGIN
    INSERT INTO @receiver (theCount)
    exec(@sql)

    UPDATE @results
    SET Longest = (SELECT theCount FROM @receiver)
    WHERE ID = @id

    DELETE FROM @receiver

    FETCH NEXT FROM length_cursor
    INTO @id, @sql
END
CLOSE length_cursor
DEALLOCATE length_cursor


SELECT 
    TableName, 
    ColumnName, 
    DataType, 
    MaxLength, 
    Longest 
FROM 
    @results
于 2013-01-24T14:47:07.523 回答
11

这是我用来分析可能有用的数据的东西。只需将“您的表名”更改为您的表名。它旨在向您展示可以修剪列的位置。

DECLARE @YourTableName sysname;
DECLARE @sql nvarchar(MAX) = ''
SET @YourTableName = YOUR TABLE NAME 
CREATE TABLE #resultsTable (columnName varchar(100), columnLargestValueInData int, columnMaxLength int)

DECLARE @whileIter int = 1
DECLARE @whileTotal int  

SELECT @whileTotal = COUNT(*) FROM sys.columns c
                            INNER JOIN 
                                sys.types t ON c.user_type_id = t.user_type_id
                            WHERE
                                c.object_id = OBJECT_ID(@YourTableName)
-- print 'whileTotal: ' + CONVERT(VARCHAR,@whileTotal) -- used for testing
WHILE @whileIter <= @whileTotal
BEGIN

SELECT  @sql =  N'INSERT INTO #resultsTable (columnName,  columnLargestValueInData, columnMaxLength) SELECT ''' + sc.name + ''' AS columnName, max(len([' + sc.name + '])), ' + CONVERT(varchar,sc.max_length) + ' FROM [' + t.name + ']'  
FROM  sys.tables AS t
INNER JOIN sys.columns AS sc ON t.object_id = sc.object_id
INNER JOIN sys.types AS st ON sc.system_type_id = st.system_type_id
WHERE column_id = @whileIter
AND t.name = @YourTableName
AND st.name IN ('char', 'varchar', 'nchar', 'nvarchar')

PRINT @sql

exec sp_executesql @sql
SET @whileIter += 1
END
SELECT * FROM #resultsTable

TRUNCATE TABLE #resultsTable
DROP TABLE #resultsTable
于 2014-06-20T21:13:13.433 回答
7

这是我使用多年的版本。它用下划线代替空格,以给出带有尾随空格的真实数据长度。

set nocount on;
declare @TableName varchar(150) = 'TableName';
declare @Schema varchar(20) = 'TableSchema';
declare @Columns varchar(max);
declare @Unpivot varchar(max);
declare @SQL varchar(max);

select  @Columns = STUFF((
select  ',max(len(replace([' + COLUMN_NAME + '],'' '',''_'')))[' + COLUMN_NAME + '/' 
        + isnull(ltrim(CHARACTER_MAXIMUM_LENGTH),DATA_TYPE) + ']' + CHAR(10) + CHAR(9)
from    INFORMATION_SCHEMA.COLUMNS
where   TABLE_SCHEMA = @Schema
        and TABLE_NAME = @TableName
order   by ORDINAL_POSITION
for XML PATH('')),1,1,'')

select  @Unpivot = STUFF((
select  ',[' + COLUMN_NAME + '/' + isnull(ltrim(CHARACTER_MAXIMUM_LENGTH),DATA_TYPE) + ']'
from    INFORMATION_SCHEMA.COLUMNS
where   TABLE_SCHEMA = @Schema
        and TABLE_NAME = @TableName
order   by ORDINAL_POSITION
for XML PATH('')),1,1,'')

select  @SQL = 
'select DataSize, ColumnName [ColumnName/Size]
from    (
        select ' + @Columns + 'from [' + @Schema + '].[' + @TableName + ']
        )x 
unpivot (DataSize for ColumnName in (' + @Unpivot + '))p'

print (@SQL)
exec (@SQL)
于 2017-01-11T20:57:29.790 回答
3
   SELECT TOP 1 WITH TIES
        Object_Name(c.object_id) ObjectName,
        c.name [Column Name],
        t.Name [Data type],
        c.max_length [Max Length]
    FROM    
        sys.columns c
    INNER JOIN 
        sys.types t ON c.system_type_id = t.system_type_id
    WHERE
        c.object_id = OBJECT_ID('MyTable')
    ORDER BY c.max_length DESC
于 2013-01-23T15:20:02.150 回答
3



我扩展了 CeejeeB 的解决方案,添加了新字段(Min、Max、NullCount 和 CountDinstict),并修复了一个用 [] 围绕 db 名称的错误。
此外,我管理了 unicode 类型的大小。

随意尝试更改后的 SQL 脚本,但请注意,因为该脚本会分析当前数据库的所有用户定义表,并且可能需要很多时间才能完成......

DECLARE @results TABLE (
    ID VARCHAR(36)
    ,TableName VARCHAR(250)
    ,ColumnName VARCHAR(250)
    ,DataType VARCHAR(250)
    ,MaxLength INT
    ,Longest INT
    ,Min VARCHAR(250)
    ,Max VARCHAR(250)
    ,NullCount BIGINT
    ,CountDistinct BIGINT
    ,SQLText VARCHAR(MAX)
    )

INSERT INTO @results (
    ID
    ,TableName
    ,ColumnName
    ,DataType
    ,MaxLength
    ,SQLText
    )
SELECT NEWID() AS ID
    ,Object_Name(c.object_id) AS TableName
    ,c.name AS ColumnName
    ,t.name AS DataType
    ,CASE 
        WHEN t.name NOT IN (
                'char'
                ,'varchar'
                ,'nchar'
                ,'nvarchar'
                ,'sysname'
                ,'text'
                )
            THEN c.max_length
        WHEN c.max_length = - 1
            THEN c.max_length
        ELSE CASE 
                WHEN t.name IN (
                        'nchar'
                        ,'nvarchar'
                        ,'sysname'
                        )
                    THEN c.max_length / 2
                ELSE c.max_length
                END
        END AS MaxLength
    ,'SELECT Max(Len(' + CASE t.name
        WHEN 'text'
            THEN 'cast('
        ELSE ''
        END + '[' + c.name + ']' + CASE t.name
        WHEN 'text'
            THEN ' as varchar(max))'
        ELSE ''
        END + ')) AS MaxLength,
        Min(' + CASE t.name
        WHEN 'bit'
            THEN 'CONVERT(int,'
        WHEN 'text'
            THEN 'cast('
        ELSE ''
        END + '[' + c.name + ']' + CASE t.name
        WHEN 'bit'
            THEN ')'
        WHEN 'text'
            THEN ' as varchar(max))'
        ELSE ''
        END + ') AS Min,
        Max(' + CASE t.name
        WHEN 'bit'
            THEN 'CONVERT(int,'
        WHEN 'text'
            THEN 'cast('
        ELSE ''
        END + '[' + c.name + ']' + CASE t.name
        WHEN 'bit'
            THEN ')'
        WHEN 'text'
            THEN ' as varchar(max))'
        ELSE ''
        END + ') AS Max, sum(case when ' + '[' + c.name + ']' + ' is null then 1 else 0 end) AS  NullCount, 
        COUNT_BIG(DISTINCT ' + CASE t.name
        WHEN 'text'
            THEN 'cast('
        ELSE ''
        END + '[' + c.name + ']' + CASE t.name
        WHEN 'text'
            THEN ' as varchar(max))'
        ELSE ''
        END + ') AS CountDistinct 
        FROM [' + OBJECT_SCHEMA_NAME(c.object_id) + '].[' + Object_Name(c.object_id) + ']' AS SQLText
FROM sys.columns c
INNER JOIN sys.types t ON c.system_type_id = t.system_type_id
INNER JOIN sys.objects o ON c.object_id = o.object_id
WHERE o.type = 'U'

DECLARE @id VARCHAR(36)
DECLARE @SQL VARCHAR(MAX)
DECLARE @receiver TABLE (
    Longest INT
    ,Min VARCHAR(250)
    ,Max VARCHAR(250)
    ,NullCount BIGINT
    ,CountDistinct BIGINT
    )

DECLARE length_cursor CURSOR
FOR
SELECT ID
    ,SQLText
FROM @results

OPEN length_cursor

FETCH NEXT
FROM length_cursor
INTO @id
    ,@SQL

WHILE @@FETCH_STATUS = 0
BEGIN
    INSERT INTO @receiver (
        Longest
        ,Min
        ,Max
        ,NullCount
        ,CountDistinct
        )
    EXEC (@SQL)

    UPDATE @results
    SET Longest = r.Longest
        ,Min = r.Min
        ,Max = r.Max
        ,NullCount = r.NullCount
        ,CountDistinct = r.CountDistinct
    FROM @receiver r
    WHERE ID = @id

    DELETE
    FROM @receiver

    FETCH NEXT
    FROM length_cursor
    INTO @id
        ,@SQL
END

CLOSE length_cursor

DEALLOCATE length_cursor

SELECT TableName
    ,ColumnName
    ,DataType
    ,MaxLength
    ,Longest
    ,Min
    ,Max
    ,NullCount
    ,CountDistinct
FROM @results
于 2018-10-19T15:07:00.197 回答
2

更正了上面的查询

SELECT 
    Object_Name(c.object_id),
    c.name 'Column Name',
    t.name 'Data type',
    c.max_length 'Max Length'
FROM    
    sys.columns c
INNER JOIN 
    sys.types t ON c.user_type_id = t.user_type_id
WHERE
    c.object_id = OBJECT_ID('tablename')
于 2014-02-20T10:41:59.460 回答
0

添加:和 t.user_type_id = 167,否则,您将获得非 varchars 的副本。我知道还有其他类型,这是针对特定表的快速修复

在 c.object_id = OBJECT_ID(@YourTableName) 之后

于 2015-04-30T22:16:57.170 回答
0

请注意,上面提到的所有查询都会报告一些“奇怪”的大小 - 特别是对于 n... 类型(nvarchar / nchar)。这个稍作修改的查询修复了这个问题:

DECLARE @tableName AS NVARCHAR(200) = 'Items'

SELECT 
    Object_Name(c.object_id) AS 'Table',
    c.name AS 'Column Name',
    t.name AS 'Data type',
    CASE WHEN t.name LIKE 'n%' THEN c.max_length / 2 ELSE c.max_length END AS 'Max Length'
FROM    
    sys.columns c
INNER JOIN 
    sys.types t ON c.user_type_id = t.user_type_id
WHERE
    c.object_id = OBJECT_ID(@tableName)
于 2017-07-07T09:11:30.657 回答
0

最后想出这个来找到表中每一列的最大数据长度和最大长度

SELECT name, max_length, MAX(DATALENGTH(name))
FROM sys.columns
WHERE OBJECT_ID = OBJECT_ID('table name')
GROUP BY name, max_length
于 2020-10-08T17:35:18.867 回答
0

按大小比较 TableA 列和 TableB 列是不够的。您必须从 tableA 获取每列数据的最大数据长度,然后将其与 TableB 列大小进行比较以找到罪魁祸首列。

于 2021-06-04T17:06:35.393 回答
0

尝试了大多数解决方案,但只有这个对我有用。感谢作者的描述。

只需将前两行更改为您的表格名称TableNameSchemaName计划您的表格所在的位置。确保您在正确的数据库上执行或只是放

Use 
yourDatabse
go

在这个脚本的开头。

/**************************************
SQL to get max length of values in every table column.

This SQL queries the specified table to get the max length
of all the values in every column.

To work, load all the incoming data into a "permanent" temporary table
where every column is defined as a varchar(max).

Then run this script against that "permanent" temporary table, comparing
the results against the original table's schema to see what column, and
then what record(s), is/are causing the issue.

Example, if the max length of a value in one of the columns is 270,
but your original table's schema is varchar(255), obviously either
the original table's schema will have to be altered or the data corrected.

Code from: http://cc.davelozinski.com
**************************************/

--The table we'll be performing this query on to get the lengths of every column.
--Default is dbo schema. Change as appropriate for your table.
DECLARE @TableName VARCHAR(200) = 'TableName'
       ,@SchemaName VARCHAR(200) = 'SchemaName'

DECLARE @MaxLengthDefault INT
       ,@Column VARCHAR(50)
       ,@MaxLength INT
       ,@MaxLengthString VARCHAR(10)
       ,@ColumnID INT
       ,@MaxColumnID INT
       ,@Command VARCHAR(2000)

CREATE TABLE #Temp (
       column_name VARCHAR(50)
       ,max_length INT
       ,max_length_default INT
)

SELECT @ColumnID = min(b.[column_id])
       ,@MaxColumnID = max(b.[column_id])
FROM sys.tables a
INNER JOIN sys.columns b on a.[object_id] = b.[object_id]
WHERE a.[name] = @TableName
       and SCHEMA_NAME(a.[schema_id]) = @SchemaName

--SELECT @ColumnID, @MaxColumnID

WHILE(@ColumnID <= @MaxColumnID)
BEGIN
    SET @Column = null

    SELECT @Column = b.[name]
              ,@MaxLengthDefault = b.[max_length]
       FROM sys.tables a
       INNER JOIN sys.columns b on a.[object_id] = b.[object_id]
       WHERE a.[name] = @TableName
              and SCHEMA_NAME(a.[schema_id]) = @SchemaName
              and b.[column_id] = @ColumnID

    --SELECT @Column, @MaxLengthDefault

    IF ( @Column is not null )
    BEGIN
              SET @Command = 'INSERT INTO #Temp(column_name, max_length, max_length_default)
                SELECT ''' + @Column + '''
                ,MAX(LEN(CAST([' + @Column + '] as VARCHAR(8000))))
                ,' + CAST(@MaxLengthDefault as VARCHAR(5)) +
                ' FROM [' + @SchemaName + '].[' + @TableName + ']
                WHERE [' + @Column + '] IS NOT NULL'
              --SELECT @Command
              EXEC(@Command)
       END

    SET @ColumnID = @ColumnID + 1
END

SELECT * FROM #Temp

DROP TABLE #Temp
于 2021-11-24T09:50:35.987 回答
-1

答案相当复杂。您需要使用动态 SQL 来组合查询或在 Excel 中完成工作。您需要将系统表中的元数据(我将使用 Information_Schema.Columns)与表本身的数据结合起来。

我的书Data Analysis Using SQL and Excel第 84-90 页解释了如何做到这一点。这个网站的答案太长了。

于 2013-01-23T15:47:09.717 回答
-2

我们可以使用以下查询来查找列名、数据类型、列长度:

SELECT owner, 
       column_name, 
       data_type, 
       data_length 
FROM   all_tab_columns 
WHERE  table_name = 'write your table name here' 
       AND owner = 'write your column name here' 
ORDER  BY column_id; 

上面的查询既可以作为普通查询也可以作为 PL/SQL 使用。

于 2020-01-23T06:35:08.383 回答
-3

稍作修改,但效果很好。

SELECT 
    Object_Name(c.object_id),
    c.name 'Column Name',
    t.name 'Data type',
    c.max_length 'Max Length',
    MAX(LEN(C.NAME))
FROM    
    sys.columns c
INNER JOIN 
    sys.types t ON c.user_type_id = t.user_type_id
WHERE
    c.object_id = OBJECT_ID('<table name>')
GROUP BY 
    Object_Name(c.object_id),
    c.name ,
    t.name ,
    c.max_length
于 2014-08-05T09:29:59.877 回答