检索存储过程的列名和类型? [重复]

问题描述 投票:0回答:2

可能重复:
检索存储过程结果集的列定义

我使用以下 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
2个回答
105
投票

[我刚刚意识到我之前已经回答过这个问题]

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

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

SQL Server 2012+

SQL Server 2012 中引入了一些新功能,使元数据发现变得更加容易。对于上述程序,我们可以做以下事情:

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

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

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

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

缺点:到目前为止(通过 SQL Server 2022),这仅适用于 first 结果集(正如函数名称所暗示的那样)。

仅FMT

在旧版本上,一种方法是做这样的事情:

SET FMTONLY ON;
GO
EXEC dbo.bar;

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

现在,

SET FMTONLY ON;
有很多问题,我不会在这里讨论,但至少 应该注意这个命令已被弃用 - 有充分的理由。做完还要注意
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
不显示长度,您必须获得其他类型的精度/比例,例如
datetime2
time
decimal
。但这是一个开始。


2
投票

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

select * from information_schema.parameters

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

获取存储过程返回的列名/类型

© www.soinside.com 2019 - 2024. All rights reserved.