在单个查询

时间:2018-01-10 22:42:31

标签: sql sql-server

我是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”

如何组合这两个查询?

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

1 个答案:

答案 0 :(得分:0)

从单一查询的角度来看,这是不可能的。但是,你可以收集基础数据并运行你的MAX(LEN())如果你之前转换为NVARCHAR(MAX),那么日期大小看起来会更真实 - 我已经在一个循环中使用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

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