sp_describe_first_result_set (Transact-SQL)

适用于:SQL ServerAzure SQL 数据库Azure SQL 托管实例Azure Synapse AnalyticsAnalytics Platform System (PDW)Microsoft Fabric 中的 SQL 分析终结点Microsoft Fabric 中的仓库

返回 Transact-SQL 批处理的第一个可能结果集的元数据。 如果批处理没有返回结果,则返回一个空的结果集。 如果数据库引擎无法确定将通过执行静态分析来执行的第一个查询的元数据,则会引发错误。 动态管理视图 sys.dm_exec_describe_first_result_set (Transact-SQL) 返回相同信息。

Transact-SQL 语法约定

语法

  
sp_describe_first_result_set [ @tsql = ] N'Transact-SQL_batch'   
    [ , [ @params = ] N'parameters' ]   
    [ , [ @browse_information_mode = ] <tinyint> ] ]  

参数

[ @tsql = ] 'Transact-SQL_batch' 一个或多个 Transact-SQL 语句。 Transact-SQL_batch 可以是 nvarchar(n) 或 nvarchar(max)。

[ @params = ] N'parameters' @params 为 Transact-SQL 批处理参数提供声明字符串,它类似于 sp_executesql。 参数可以是 nvarchar(n) 或 nvarchar (max)。

一个字符串,它包含 Transact-SQL_batch 中嵌入的所有参数的定义。 字符串必须是 Unicode 常量或 Unicode 变量。 每个参数定义由参数名称和数据类型组成。 n 是表示附加参数定义的占位符。 在语句中指定的每个参数都必须在 @params 中定义。 如果语句中的 Transact-SQL 语句或批处理不包含参数,则不需要使用 @params。 该参数的默认值为 NULL。

[ @browse_information_mode = ] tinyint 指定是否返回其他键列和源表信息。 如果设置为 1,则分析每个查询,就好像它在查询中包含 FOR BROWSE 选项一样。 将返回其他键列和源表信息。

  • 如果设置为 0,则无信息返回。

  • 如果设置为 1,则分析每个查询,就好像它在查询中包含 FOR BROWSE 选项一样。 该参数将返回用作源列信息的基表名称。

  • 如果设置为 2,则分析每个查询,就好像它用于准备或执行游标一样。 该参数将返回用作源列信息的视图名称。

返回代码值

sp_describe_first_result_set 始终对成功返回状态零。 如果该过程引发错误并且此过程作为 RPC 进行调用,则返回状态将由 sys.dm_exec_describe_first_result_set 的 error_type 列中描述的错误类型填充。 如果从 Transact-SQL 中调用此过程,则返回值始终为零,甚至在出现错误时也不例外。

结果集

此公共元数据作为结果集返回,结果元数据中的每列对应于一行。 每一行以下面一节所说明的格式描述列的类型和为 Null 性。 如果对于每个控制路径不存在第一个语句,则返回的结果集不包含任何行。

列名称 数据类型 说明
is_hidden bit(非 NULL) 指示列是出于浏览信息目的而额外添加的列,该列不会实际显示在结果集中。
column_ordinal int NOT NULL 在结果集中包含列的序号位置。 第一列的位置将指定为 1。
name sysname NULL 包含列的名称(如果可以确定名称)。 否则,它将包含 NULL。
is_nullable bit(非 NULL) 如果列允许 NULL,则包含值 1;如果列不允许 NULL,则包含 0;如果不能确定列是否允许 NULL,则为 1。
system_type_id int NOT NULL 包含在 sys.types 中指定的列数据类型的 system_type_id。 对于 CLR 类型,即使 system_type_name 列返回 NULL,该列也会返回值 240。
system_type_name nvarchar(256) NULL 包含为列数据类型指定的名称和参数(例如,length、precision、scale)。 如果数据类型是用户定义的别名类型,则会在此处指定基本系统类型。 如果数据类型是 CLR 用户定义类型,则在此列中返回 NULL。
max_length smallint(非 NULL) 列的最大长度(字节)。

-1 = 列数据类型是 varchar(max)、nvarchar(max)、varbinary(max) 或 xml。

对于文本列,max_length 值将是 16 或是由 sp_tableoption“text in row”设置的值。
精度 tinyint(非 NULL) 如果为基于数值的列,则为该列的精度。 否则,返回 0。
scale tinyint(非 NULL) 如果基于数值,则为列的小数位数。 否则,返回 0。
collation_name sysname NULL 如果列包含的是字符,则为该列的排序规则的名称。 否则,返回 NULL。
user_type_id int NULL 对于 CLR 和别名类型,包含在 sys.types 中指定的列数据类型的 user_type_id。 否则为 NULL。
user_type_database sysname NULL 对于 CLR 和别名类型,包含在其中定义相应类型的数据库的名称。 否则为 NULL。
user_type_schema sysname NULL 对于 CLR 和别名类型,包含在其中定义相应类型的架构的名称。 否则为 NULL。
user_type_name sysname NULL 对于 CLR 和别名类型,包含类型的名称。 否则为 NULL。
assembly_qualified_type_name nvarchar(4000) 对于 CLR 类型,返回定义类型的程序集和类的名称。 否则为 NULL。
xml_collection_id int NULL 包含 sys.columns 中指定的列数据类型的 xml_collection_id。 如果返回的类型与 XML 架构集合不关联,则该列将返回 NULL。
xml_collection_database sysname NULL 包含定义与此类型关联的 XML 架构集合的数据库。 如果返回的类型与 XML 架构集合不关联,则该列将返回 NULL。
xml_collection_schema sysname NULL 包含定义与此类型关联的 XML 架构集合的架构。 如果返回的类型与 XML 架构集合不关联,则该列将返回 NULL。
xml_collection_name sysname NULL 包含与此类型关联的 XML 架构集合的名称。 如果返回的类型与 XML 架构集合不关联,则该列将返回 NULL。
is_xml_document bit(非 NULL) 如果返回的数据类型为 XML,并且保证该类型是完整的 XML 文档(包含根节点,与 XML 片段相对),则返回 1。 否则,返回 0。
is_case_sensitive bit(非 NULL) 如果列为区分大小写的字符串类型,则返回 1;否则为 0。
is_fixed_length_clr_type bit(非 NULL) 如果列为固定长度 CLR 类型,则返回 1;否则为 0。
source_server sysname 此结果中的此列返回的源服务器的名称(如果结果源自远程服务器)。 将按照 sys.servers 中显示的形式指定名称。 如果列来自本地服务器或无法确定它来自的服务器,则返回 NULL。 仅在请求浏览信息时填充它。
source_database sysname 此结果中的列返回的源数据库的名称。 如果无法确定该数据库,则返回 NULL。 仅在请求浏览信息时填充它。
source_schema sysname 此结果中的列返回的源架构的名称。 如果无法确定该架构,则返回 NULL。 仅在请求浏览信息时填充它。
source_table sysname 此结果中的列返回的源表的名称。 如果无法确定该表,则返回 NULL。 仅在请求浏览信息时填充它。
source_column sysname 结果列返回的源列的名称。 如果无法确定该列,则返回 NULL。 仅在请求浏览信息时填充它。
is_identity_column bit NULL 如果列是标识列,则返回 1;否则,返回 0。 如果无法确定列是否为标识列,则返回 NULL。
is_part_of_unique_key bit NULL 如果列是唯一索引的一部分(包括唯一和主要的约束),则返回 1;否则,返回 0。 如果无法确定列是否为唯一索引的一部分,则返回 NULL。 仅在请求浏览信息时填充它。
is_updateable bit NULL 如果可以更新列,则返回 1;否则,返回 0。 如果无法确定是否可以更新列,则返回 NULL。
is_computed_column bit NULL 如果列是计算列,则返回 1;否则,返回 0。 如果无法确定列是否为计算列,则返回 NULL。
is_sparse_column_set bit NULL 如果列是稀疏列,则返回 1;否则,返回 0。 如果无法确定列是否为稀疏列集的一部分,则返回 NULL。
ordinal_in_order_by_list smallint NULL 此列在 ORDER BY 列表中的位置。 如果在 ORDER BY 列表中不显示该列或无法唯一确定 ORDER BY 列表,则返回 NULL。
order_by_list_length smallint NULL ORDER BY 列表的长度。 如果没有 ORDER BY 列表,或者无法唯一确定 ORDER BY 列表,则返回 NULL。 请注意,对于 sp_describe_first_result_set 返回的所有行,该值是相同的。
order_by_is_descending smallint NULL 如果 ordinal_in_order_by_list 不为 NULL,则 order_by_is_descending 列报告此列的 ORDER BY 子句的方向。 否则,它报告 NULL。
tds_type_id int NOT NULL 供内部使用。
tds_length int NOT NULL 供内部使用。
tds_collation_id int NULL 供内部使用。
tds_collation_sort_id tinyint NULL 供内部使用。

备注

sp_describe_first_result_set 确保如果此过程返回某个假设批处理 A 的第一个结果集元数据,并且后续执行批处理 (A),则此批处理架构出现以下任一行为:(1) 引发优化时错误;(2) 引发运行时错误;(3) 不返回结果集;或者 (4) 返回第一个结果集,其中具有 sp_describe_first_result_set 描述的相同元数据。

名称、为 Null 性和数据类型可能不同。 如果 sp_describe_first_result_set 返回空结果集,则可保证批处理执行将不返回结果集。

此保证假定在服务器上没有相关的架构更改。 服务器上的相关架构更改不包括在调用 sp_describe_first_result_set 的时间与在执行期间返回结果集的时间之间,在批处理 A 中创建临时表或表变量,但包括批处理 B 进行的架构更改。

sp_describe_first_result_set 在以下任一一种情况下都会返回错误。

  • 如果输入 @tsql 不是有效的 Transact-SQL 批处理。 有效性通过解析和分析 Transact-SQL 批处理来确定。 当确定 Transact-SQL 批处理是否有效时,将不考虑由批处理在查询优化或执行过程中导致的任何错误。

  • 如果 @params 不为 NULL,并且包含的某个字符串在语法上不是有效的参数声明字符串,或者如果它包含一个将任何参数声明多次的字符串。

  • 如果输入 Transact-SQL 批处理声明的某个局部变量与在 @params 中声明的某个参数同名。

  • 如果该语句将使用某个临时表。

  • 查询包括创建随后要查询的永久表。

如果所有其他检查都获得成功,则将考虑输入批处理内所有可能的控制流路径。 这会考虑所有控制流语句(GOTO、IF/ELSE、WHILE 和 Transact-SQL TRY/CATCH 块)以及任何过程、动态 Transact-SQL 批处理或触发器,它们是由以下语句从输入批处理中调用的:EXEC 语句、DDL 语句(导致激发 DDL)或 DML 语句(导致对目标表或由于对外键约束执行层叠操作而修改的表激发触发器)。 在很多可能的控制路径的情况下,算法将在某个点停止。

对于每个控制流路径,返回结果集的第一个语句(如果有)将由 sp_describe_first_result_set 确定。

当在一个批处理中找到多个可能的第一个语句时,其结果可能在列数、列名称、为 Null 性以及数据类型等方面存在不同。 此处详细介绍了如何处理这些差异:

  • 如果列数不同,则会引发一个错误,但不返回任何结果。

  • 如果列名称不同,则返回的列名称将设置为 NULL。

  • 如果为 Null 性不同,则返回的为 Null 性将允许 NULL。

  • 如果数据类型不同,则将引发错误而不返回任何结果,但以下情况除外:

    • varchar(a) 到 varchar(a'),其中 a' > a。

    • varchar(a) 到 varchar(max)

    • nvarchar(a) 到 nvarchar(a'),其中 a' > a。

    • nvarchar(a) 到 nvarchar(max)

    • varbinary(a) 到 varbinary(a'),其中 a' > a。

    • varbinary(a) 到 varbinary(max)

sp_describe_first_result_set 不支持间接递归。

权限

要求具有执行 @tsql 参数的权限。

示例

典型示例

A. 简单示例

下面的示例描述从单个查询中返回的结果集。

sp_describe_first_result_set @tsql = N'SELECT object_id, name, type_desc FROM sys.indexes'  

下面的示例显示了从包含一个参数的单个查询中返回的结果集。

sp_describe_first_result_set @tsql =   
N'SELECT object_id, name, type_desc   
FROM sys.indexes   
WHERE object_id = @id1'  
, @params = N'@id1 int'  

B. 浏览模式示例

以下三个示例演示了不同浏览信息模式之间的主要差异。 只有相关的列会包含在查询结果中。

以下示例使用 0,指示无信息返回。

CREATE TABLE dbo.t (a int PRIMARY KEY, b1 int);  
GO  
CREATE VIEW dbo.v AS SELECT b1 AS b2 FROM dbo.t;  
GO  
EXEC sp_describe_first_result_set N'SELECT b2 AS b3 FROM dbo.v', null, 0;  

下面是结果集:

is_hidden column_ordinal name source_schema source_table source_column is_part_of_unique_key
0 1 b3 Null Null Null Null

以下示例使用 1,指示它将返回信息,就好像它在查询中包含 FOR BROWSE 选项一样。

EXEC sp_describe_first_result_set N'SELECT b2 AS b3 FROM v', null, 1  
  

下面是结果集:

is_hidden column_ordinal name source_schema source_table source_column is_part_of_unique_key
0 1 b3 dbo t B1 0
1 2 a dbo t a 1

以下示例使用 2,指示执行分析,就好像您在准备游标一样。

EXEC sp_describe_first_result_set N'SELECT b2 AS b3 FROM v', null, 2  

下面是结果集:

is_hidden column_ordinal name source_schema source_table source_column is_part_of_unique_key
0 1 B3 dbo v B2 0
1 2 ROWSTAT Null Null Null 0

C. 将结果存储在表中

在某些情况下,需要将 sp_describe_first_result_set 过程的结果放在某个表中,以便可以进一步处理架构。 首先,需要创建一个与 sp_describe_first_result_set 过程输出匹配的表:

create table #frs (
    is_hidden bit not null,
    column_ordinal int not null,
    name sysname null,
    is_nullable bit not null,
    system_type_id int not null,
    system_type_name nvarchar(256) null,
    max_length smallint not null,
    precision tinyint not null,
    scale tinyint not null,
    collation_name sysname null,
    user_type_id int null,
    user_type_database sysname null,
    user_type_schema sysname null,
    user_type_name sysname null,
    assembly_qualified_type_name nvarchar(4000),
    xml_collection_id int null,
    xml_collection_database sysname null,
    xml_collection_schema sysname null,
    xml_collection_name sysname null,
    is_xml_document bit not null,
    is_case_sensitive bit not null,
    is_fixed_length_clr_type bit not null,
    source_server sysname null,
    source_database sysname null,
    source_schema sysname null,
    source_table sysname null,
    source_column sysname null,
    is_identity_column bit null,
    is_part_of_unique_key bit null,
    is_updateable bit null,
    is_computed_column bit null,
    is_sparse_column_set bit null,
    ordinal_in_order_by_list smallint null,
    order_by_list_length smallint null,
    order_by_is_descending smallint null,
    tds_type_id int not null,
    tds_length int not null,
    tds_collation_id int null,
    tds_collation_sort_id tinyint null
);

创建表时,可以将某个查询的架构存储在该表中。

declare @tsql nvarchar(max) = 'select top 0 * from sys.credentials';

insert #frs
exec sys.sp_describe_first_result_set @tsql;

select * from #frs;

问题示例

下面的示例对所有示例使用两个表。 请执行以下语句以创建示例表。

CREATE TABLE dbo.t1 (a int NULL, b varchar(10) NULL, c nvarchar(10) NULL);  
CREATE TABLE dbo.t2 (a smallint NOT NULL, d varchar(20) NOT NULL, e int NOT NULL);  

由于列数不同而出错

在此示例中,可能的第一个结果集中的列数不同。

sp_describe_first_result_set @tsql =   
N'  
IF(1=1)  
    SELECT a FROM t1;  
ELSE  
    SELECT a, b FROM t1;  
SELECT * FROM t; -- Ignored, not a possible first result set.'  
  

由于数据类型不同而出错

列类型在不同的第一个可能结果集中不同。

sp_describe_first_result_set @tsql =   
N'  
IF(1=1)  
    SELECT a FROM t1;  
ELSE  
    SELECT a FROM t2;  

结果:错误,类型不匹配(int 与 smallint)。

无法确定列名称

对于同一个变量长度类型、为 Null 性以及列名称,可能的第一个结果集的列因长度不同而不同:

sp_describe_first_result_set @tsql =   
N'  
IF(1=1)  
    SELECT b FROM t1;  
ELSE  
    SELECT d FROM t2; '  

结果:<未知列名>varchar(20) NULL

通过别名强制列名称完全相同

与前面的例子相同,但通过列别名,列具有相同名称。

sp_describe_first_result_set @tsql =   
N'  
IF(1=1)  
    SELECT b FROM t1;  
ELSE  
    SELECT d AS b FROM t2;'  

结果:bvarchar(20)NULL

由于列类型无法匹配而出错

列类型在不同的第一个可能结果集中不同。

sp_describe_first_result_set @tsql =   
N'  
IF(1=1)  
    SELECT b FROM t1;  
ELSE  
    SELECT c FROM t1;'  

结果:错误,类型不匹配(varchar(10) 与 nvarchar(10))。

结果集可以返回一个错误

第一次结果集是错误或结果集。

sp_describe_first_result_set @tsql =   
N'  
IF(1=1)  
    RAISERROR(''Some Error'', 16, 1);  
  
ELSE  
    SELECT a FROM t1;  
SELECT e FROM t2; -- Ignored, not a possible first result set.;'  

结果:intNULL

某些代码路径不返回任何结果

第一次结果集是 Null 或结果集。

sp_describe_first_result_set @tsql =   
N'  
IF(1=1)  
    RETURN;  
SELECT a FROM t1;'  

结果:intNULL

动态 SQL 中的结果

第一个结果集是可发现的动态 SQL,因为它是文字字符串。

sp_describe_first_result_set @tsql =   
N'EXEC(N''SELECT a FROM t1'');'  

结果:INT NULL

动态 SQL 中的结果失败

第一个结果集因为动态 SQL 而未定义。

sp_describe_first_result_set @tsql =   
N'  
DECLARE @SQL NVARCHAR(max);  
SET @SQL = N''SELECT a FROM t1 WHERE 1 = 1 '';  
IF(1=1)  
    SET @SQL += N'' AND e > 10 '';  
EXEC(@SQL); '  

结果:错误。 结果由于动态 SQL 而无法发现。

用户指定的结果集

第一个结果集由用户手动指定。

sp_describe_first_result_set @tsql =   
N'  
DECLARE @SQL NVARCHAR(max);  
SET @SQL = N''SELECT a FROM t1 WHERE 1 = 1 '';  
IF(1=1)  
    SET @SQL += N'' AND e > 10 '';  
EXEC(@SQL)  
    WITH RESULT SETS(  
        (Column1 BIGINT NOT NULL)  
    ); '  

结果:Column1 bigint NOT NULL

由不明确结果集引起的错误

本示例假定名为 user1 的另一个用户在具有列 (int NOT NULL) 的默认架构 s1 中具有名为 t1 的表 。

sp_describe_first_result_set @tsql =   
N'  
    IF(@p > 0)  
    EXECUTE AS USER = ''user1'';  
    SELECT * FROM t1;'  
, @params = N'@p int'  

结果:错误。 t1 可以是 dbo.t1 或 s1.t1,每个具有不同数目的列。

在使用不明确的结果集时的结果

与前一个示例采用相同的假设。

sp_describe_first_result_set @tsql =   
N'  
    IF(@p > 0)  
    EXECUTE AS USER = ''user1'';  
    SELECT a FROM t1;'  

结果:int NULL,因为 dbo.t1.a 和 s1.t1.a 同时具有类型 int 和不同的为 Null 性。

另请参阅

sp_describe_undeclared_parameters (Transact-SQL)
sys.dm_exec_describe_first_result_set (Transact-SQL)
sys.dm_exec_describe_first_result_set_for_object (Transact-SQL)