【问题标题】:Finding the longest string, data type, data type value along with the column name in a single query在单个查询中查找最长的字符串、数据类型、数据类型值以及列名
【发布时间】:2018-06-20 04:56:06
【问题描述】:

我是 SQL 新手,整天都在尝试解决这个问题。 我正在尝试为 SQL 服务器创建一个 SQL 查询,以列出正在查询的表中的每个列名、该列的数据类型、为该数据类型设置的数量(例如:nvarchar(255))以及最长的字符串在该列中全部在一个查询中。

到目前为止,我有这个:

DECLARE @Table VARCHAR(200) = 'Customer'

SELECT column_name AS ColumnName, data_type AS DataType, CHARACTER_MAXIMUM_LENGTH AS CharacterSetLength, NUMERIC_PRECISION AS NumericSetLength
FROM   information_schema.columns
WHERE  table_name = @Table
ORDER  BY ordinal_position

我也一直在使用 MAX(LEN(column_name)) 来查找该列中最长的字符串,但我认为这不是查询最长字符串的正确方法,因为我得到“21”作为当最长日期只有 10 个字符时,“日期”的结果:“2017-05-17”

如何组合这两个查询?

查询一列中最长字符串的正确方法是什么?

【问题讨论】:

  • 您将需要动态 SQL(或可能是 XML hack)。至于日期,无论如何您都不希望将其存储在可变长度列中。

标签: sql sql-server


【解决方案1】:

从我的角度来看,一个查询是不可能的。但是,如果您之前转换为 NVARCHAR(MAX),您可以收集基本数据并运行您的 MAX (LEN()),那么日期大小会看起来更真实 - 我已经在循环中使用 try-catch万一演员失败。下面是一个示例(我使用了架构名称以防您想区分表)

DECLARE @Table VARCHAR(255) = 'Customer'
DECLARE @Schema VARCHAR(255) = 'dbo'

DECLARE @i INT
DECLARE @j INT 
DECLARE @sql NVARCHAR(MAX)
DECLARE @buffer TABLE (buffer_value VARCHAR(255))
DECLARE @actual_max_size INT
DECLARE @sch_table_name VARCHAR(255)
DECLARE @column_name VARCHAR(255)
DECLARE @TbList TABLE ( 
    id INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, 
    sch_name VARCHAR(255),
    table_name VARCHAR(255),
    column_name VARCHAR(255),
    datatype_name VARCHAR(255),
    type_length INT,
    actual_max_size INT )

INSERT INTO @TbList 
(   sch_name ,
    table_name ,
    column_name ,
    datatype_name ,
    type_length )
SELECT 
    s.name AS sch_name,
    t.name AS table_name,
    c.name AS column_name,
    y.name AS datatype_name,
    c.max_length AS type_length
FROM sys.tables t
JOIN sys.schemas s
ON t.schema_id = s.schema_id
JOIN sys.columns c
ON t.object_id = c.object_id
JOIN sys.types y
ON c.user_type_id = y.user_type_id 
WHERE t.name = @Table
AND s.name = @Schema 

SET @i = (SELECT MIN(id) FROM @TbList )
SET @j = (SELECT MAX(id) FROM @TbList )
WHILE @i <= @j
BEGIN 
    DELETE FROM @buffer 
    SET @sch_table_name = (SELECT sch_name+'.'+table_name FROM @TbList WHERE id = @i)
    SET @column_name = (SELECT column_name FROM @TbList WHERE id = @i)
    SET @sql = ('SELECT MAX(LEN(CAST ('+@column_name+' AS NVARCHAR(MAX)))) FROM '+@sch_table_name+'')
    BEGIN TRY 
        INSERT INTO @buffer (buffer_value) EXEC (@sql) 
        SET @actual_max_size = (SELECT TOP 1 buffer_value FROM @buffer)
    END TRY
    BEGIN CATCH 
        SET @actual_max_size = -1
        PRINT ERROR_MESSAGE()
    END CATCH
    IF @actual_max_size IS NULL
    BEGIN 
        SET @actual_max_size = 0
    END 
    UPDATE @TbList SET actual_max_size = @actual_max_size WHERE id = @i
    SET @i = @i+1
END 
SELECT * FROM @TbList

几个 cmets:我使用循环来一一获取每一列的 MAX LEN。这不是最优雅的方法,但效果很好。如果桌子很大,可能需要一些时间。 注意:要在循环中运行查询,我们必须在动态 SQL 中进行。那么问题就是将动态 SQL 的输出带回主查询并更新内存表。 sp_executesql 可以做到这一点,但我发现上面的解决方案更快: 我的解决方案是基于我们可以将动态 SQL 查询的输出插入到表中的原理。然后我创建一个缓冲区表来存储查询结果,并使用该缓冲区表中的 select top 1 更新变量(在循环开始时清空)。不是很优雅,但工作正常。

【讨论】:

  • 您是否有机会将此答案用于 MySQL V 5.6.nn 或您可以/将要发布的更新版本?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多