【问题标题】:Retrieve column names and types of a stored procedure? [duplicate]检索存储过程的列名和类型? [复制]
【发布时间】:2013-01-12 13:02:30
【问题描述】:

可能重复:
Retrieve column definition for stored procedure result set

我使用以下 SQL 来获取表或视图的列名和类型:

DECLARE @viewname varchar (250);

select a.name as colname,b.name as typename 
from syscolumns a, systypes b -- GAH!
where a.id = object_id(@viewname) 
and a.xtype=b.xtype 
and b.name <> 'sysname'

如何对存储过程的输出列执行类似操作?

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    [我刚刚意识到我已经answered this question before]

    为存储过程执行此操作比为视图或表执行此操作要复杂得多。问题之一是存储过程可以有多个不同的代码路径,具体取决于输入参数,甚至是您无法控制的东西,例如服务器状态、一天中的时间等。例如,您希望看到的输出这个存储过程?如果不考虑条件有多个结果集怎么办?

    CREATE PROCEDURE dbo.foo
      @bar INT
    AS
    BEGIN
      SET NOCOUNT ON;
    
      IF @bar = 1
        SELECT a, b, c FROM dbo.blat;
      ELSE
        SELECT d, e, f, g, h FROM dbo.splunge;
    END
    GO
    

    如果您的存储过程没有代码路径,并且您确信您将始终看到相同的结果集(并且可以提前确定如果存储过程具有非可选参数则应提供哪些值),让我们采取简单的例子:

    CREATE PROCEDURE dbo.bar
    AS
    BEGIN
      SET NOCOUNT ON;
    
      SELECT a = 'a', b = 1, c = GETDATE();
    END
    GO
    

    FMTONLY

    一种方法是这样做:

    SET FMTONLY ON;
    GO
    EXEC dbo.bar;
    

    这将为您提供一个空结果集,您的客户端应用程序可以查看该结果集的属性以确定列名和数据类型。

    现在,SET FMTONLY ON; 有很多问题我不会在这里讨论,但至少 it should be noted that this command is deprecated - 有充分的理由。完成后还要小心SET FMTONLY OFF;,否则您会想知道为什么您成功创建存储过程但无法执行它。不,我不会警告你,因为它只是发生在我身上。诚实的。 :-)

    打开查询

    通过创建环回链接服务器,您可以使用OPENQUERY 之类的工具来执行存储过程,但返回您可以检查的可组合结果集(好吧,请接受这是一个非常松散的定义)。首先创建一个环回服务器(假设本地实例名为FOO):

    USE master;
    GO
    EXEC sp_addlinkedserver @server = N'.\FOO', @srvproduct=N'SQL Server'
    GO
    EXEC sp_serveroption @server=N'.\FOO', @optname=N'data access', 
      @optvalue=N'true';
    

    现在我们可以采用上述过程并将其输入到这样的查询中:

    SELECT * INTO #t 
    FROM OPENQUERY([.\FOO], 'EXEC dbname.dbo.bar;')
    WHERE 1 = 0;
    
    SELECT c.name, t.name
    FROM tempdb.sys.columns AS c
    INNER JOIN sys.types AS t
    ON c.system_type_id = t.system_type_id
    WHERE c.[object_id] = OBJECT_ID('tempdb..#t');
    

    这将忽略别名类型(以前称为用户定义的数据类型),并且还可能为定义为 sysname 的列显示两行。但从上面它产生:

    name   name
    ----   --------
    b      int
    c      datetime
    a      varchar
    

    显然这里还有更多工作要做 - varchar 不显示长度,您必须获得其他类型的精度/比例,例如 datetime2timedecimal。但这是一个开始。

    SQL Server 2012

    SQL Server 2012 中的一些新功能使元数据发现变得更加容易。对于上述过程,我们可以执行以下操作:

    SELECT name, system_type_name
    FROM sys.dm_exec_describe_first_result_set_for_object
    (
      OBJECT_ID('dbo.bar'), 
      NULL
    );
    

    除其他外,这实际上为我们提供了精度和规模,并解析了别名类型。对于上述过程,这会产生:

    name   system_type_name
    ----   ----------------
    a      varchar(1)
    b      int
    c      datetime
    

    视觉上没有太大区别,但是当您开始使用各种精度和规模的所有不同数据类型时,您会欣赏此功能为您所做的额外工作。

    缺点:在 SQL Server 2012 中,至少这些函数仅适用于 first 结果集(正如函数名称所暗示的那样)。

    【讨论】:

    • 谢谢,这是一个写得很好的答案。我试图使用您的最后一个解决方案(“SQL Server 2012”),但有几个因素阻止它工作。如果您显示实际的执行计划,它将不起作用。如果将其包装在自己的函数中,它似乎也不起作用。 SQL Prompt 说签名是RETURN SELECT * FROM OPENROWSET(TABLE DMF_SP_DESCRIBE_FIRST_RESULT_SET_OBJECT, @object_id, @browse_information_mode),但这似乎没有执行。我可以让它工作的唯一方法是直接在没有实际执行计划的查询窗口中运行它。
    • 我最终把它放在了一个 Sproc 中,它似乎可以工作,但另一个会阻止它工作的因素是你的结果是否来自 #TEMP
    • 您的 SQL Server 2012 答案简洁明了,并且至少适用于简单的存储过程。
    • 您还可以将 is_nullable 添加到 SELECT 中,如果您使用它来映射到 .NET 类型,例如 Guid?int?,这将非常有用
    • SQL server 2012 查询对我不起作用
    【解决方案2】:

    您是否尝试返回所有存储过程及其所有参数?像这样的东西应该可以解决这个问题。

    select * from information_schema.parameters
    

    如果您需要获取从存储过程返回的列,请看这里:

    Get column names/types returned from a stored procedure

    【讨论】:

    • 谢谢你。这是一个很棒的查询。我从来没有见过这个,它是如此丰富的信息! @sgeddes
    • 除了这个只列出参数而不是列。 select * from information_schema.columns(列出了很棒的列信息!)@sgeddes
    猜你喜欢
    • 2012-04-10
    • 1970-01-01
    • 2014-12-24
    • 1970-01-01
    • 2011-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-03
    相关资源
    最近更新 更多