【问题标题】:Is there a quick way to view the size of an existing column when writing a query?编写查询时是否有快速查看现有列大小的方法?
【发布时间】:2015-04-28 08:48:19
【问题描述】:

我正在将一些 SSRS 报告中的大量嵌入式 SQL 传输到函数。该过程通常涉及获取当前选择查询、添加 INSERT INTO 部分并返回结果表。像这样的:

CREATE FUNCTION [dbo].[MyReportFunction]
(
    @userid        varchar(255),
    @location      varchar(255),
    more params here...
)

RETURNS @Results TABLE
(
    Title        nvarchar(max),
    Location     nvarchar(255),
    more columns here...
)
AS
BEGIN
    INSERT INTO @Results (Title, Location, more columns...)
    SELECT tblA.Title, tblB.Location, more columns...
    FROM TableA tblA
    INNER JOIN TableB tblB
    ON tblA.Id = tblB.Id
    WHERE tblB.Location = @location

    RETURN

END

作为其中的一部分,我必须将列放入@Results 表中,并根据 SELECT 查询返回的内容为它们提供正确的大小和类型。现在获取类型很好,因为我可以将现有的 SELECT 查询复制并粘贴到一个新查询中,然后将鼠标悬停在列名上以获取它,例如列标题(nvarchar,null)。但是,我还需要知道大小。有没有一种简单的方法可以做到这一点,而不必去特定的表并查看列列表?是否有一种方法可以编辑工具提示及其在鼠标悬停时显示的信息?

如果我有很多不同表的连接,并且要滚动浏览一长串表可能会很烦人。

我使用的是 SQL Server 2008 R2

【问题讨论】:

    标签: sql sql-server sql-server-2008-r2 sql-function


    【解决方案1】:

    您可以简单地查询 INFORMATION_SCHEMA.COLUMNS 视图:

    SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE TABLE_NAME IN('TableA', 'TableB')
    AND COALESCE(CHARACTER_MAXIMUM_LENGTH, -1) > 0 
    

    我通过将CHARACTER_MAXIMUM_LENGTH 上的条件添加到结果集中进一步过滤了结果。
    这将只为您提供具有最大长度的列(varchar、char、nvarchar 等)。
    我希望这会有所帮助。

    【讨论】:

    • 这看起来还是有点麻烦,因为有些表有很多列,我需要滚动它们来检查大小。我想我可能也可以搜索列名,但这并不是我所希望的“快速提示”。
    • 对我来说似乎是个好方法
    • @t-clausen.dk - 它可能比每次滚动到我的不同表格要快,但并不是我希望的那样。如果没有更好的答案,我会将其标记为最佳答案。
    【解决方案2】:

    正如Zohar 建议的那样,您可以使用INFORMATION_SCHEMA.COLUMNS,然后让查询引擎为您完成繁重的工作

    SELECT TOP 0 * INTO #Temp FROM ( OriginalQuery ) o
    SELECT column_name+' ' + 
            data_type + 
            case data_type
                when 'sql_variant' then ''
                when 'text' then ''
                when 'ntext' then ''
                when 'xml' then ''
                when 'decimal' then '(' + cast(numeric_precision as varchar) + ', ' + cast(numeric_scale as varchar) + ')'
                else coalesce('('+case when character_maximum_length = -1 then 'MAX' else cast(character_maximum_length as varchar) end +')','') 
            end +
            case when exists ( 
                select id from syscolumns
                where object_name(id)=TABLE_NAME
                and name=column_name
                and columnproperty(id,name,'IsIdentity') = 1 
                ) then
                ' IDENTITY(' + 
                cast(ident_seed(TABLE_NAME) as varchar) + ',' + 
                cast(ident_incr(TABLE_NAME) as varchar) + ')'
                else ''
            end + 
             (case when IS_NULLABLE = 'No' then ' NOT ' else ' ' end ) + 'NULL' + 
              case when tempdb.INFORMATION_SCHEMA.COLUMNS.COLUMN_DEFAULT IS NOT NULL THEN ' DEFAULT '+ tempdb.information_schema.columns.COLUMN_DEFAULT ELSE '' END + ',' 
    FROM tempdb.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME LIKE '#Temp%'
    DROP TABLE #TEMP
    

    【讨论】:

    • 非常好!我希望我自己能考虑一下:-)
    • 可能的改进:构造一个列定义而不是仅仅转储 COLUMNS 视图,例如取自 stackoverflow.com/questions/21547/…
    • 现在您所要做的就是将其打包到一个存储过程或一个函数中,该函数将接收原始查询作为参数并返回列定义以供使用,然后您就完成了。如果可以的话,我会再次投票。
    • 有趣。我稍后会对此进行测试。谢谢。
    • 我对此有点困惑。如何插入当前查询?对不起,我很愚蠢,但我尝试了一些基本的东西,比如 SELECT TOP 0, JobNumber FROM MyTable INTO #Temp FROM Tables 但在第一个逗号和“INTO”附近出现语法错误。我已经尝试过解决这个问题,但我仍然遇到语法错误。我唯一的借口是我还没有喝咖啡……
    【解决方案3】:

    由于您的函数似乎只包含 INSERT ... SELECTRETURN,您可以将其更改为内联 TVF。这并不能真正回答您的问题,但它可能会解决首先需要知道确切数据类型的潜在问题:

    DROP FUNCTION [dbo].[MyReportFunction]
    -- multi-statement TVF and inline TVF are different object types,
    -- so ALTER will not work, you have to drop and re-create the object
    GO
    
    CREATE FUNCTION [dbo].[MyReportFunction]
    (
        @userid        varchar(255),
        @location      varchar(255),
        more params here...
    )
    
    RETURNS TABLE
    AS
    RETURN
    (
        SELECT tblA.Title, tblB.Location, more columns...
        FROM TableA tblA
        INNER JOIN TableB tblB
        ON tblA.Id = tblB.Id
        WHERE tblB.Location = @location
    )
    

    您不仅不必担心由于此切换而导致的显式数据类型声明,而且您还将获得一个对查询优化器更透明的函数。如果使用该函数的查询很复杂,而不仅仅是SELECT * FROM dbo.MyReportFunction(...),优化器将能够将该函数的查询与主查询混合以获得更好的执行计划。

    【讨论】:

    • 我不需要权限来先创建 tvp 类型吗?我不确定我有那个。如果我这样做了,我很确定 DBA 不会希望我这样做。但是我可以看到好处。
    • 嗯,我不是在谈论数据类型,而是在谈论对象类型(或者我应该说,对象种类)。因此,这与 TVP 无关,而只是 TVF(表值函数)。你的和我的都是 TVF,只有你的是多语句,我的是内联。对于 SQL Server,它们是不同类型的对象,这就是为什么您必须 DROP 多语句函数并将其作为内联函数再次创建(而不是仅仅更改它)。很抱歉造成这种混乱。
    • 无论如何,我的回答中根本没有考虑权限问题。如果您也没有创建函数的权限,这可能确实不适合您。再次抱歉。
    • 不,我的错是没有正确阅读。我看到 TVP 而不是 TVF 并立即开始研究并进行了更多研究。我有权创建函数和 sp,所以这会起作用。我再看一下。
    【解决方案4】:

    使用SQL_VARIANT_PROPERTY:

    SELECT top 1
        SQL_VARIANT_PROPERTY(colname, 'BaseType') BaseType, 
        SQL_VARIANT_PROPERTY(colname, 'Precision') [Precision], 
        SQL_VARIANT_PROPERTY(colname, 'Scale') Scale, 
        SQL_VARIANT_PROPERTY(colname, 'MaxLength') [MaxLength]
    FROM yourtable
    

    结果可能是:

    BaseType  Precision  Scale  MaxLength
    int       10         0      4
    

    【讨论】:

    • 这是有用的信息,但仍然相当麻烦。我仍然需要为我不确定大小(很多!)的每一列以及每个表更改此查询,到最后我可能会更好地滚动到表/s并看着列。我开始觉得这不能“快速简单”地完成。
    猜你喜欢
    • 1970-01-01
    • 2018-01-03
    • 2011-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    相关资源
    最近更新 更多