sp_describe_first_result_set (Transact-SQL)
返回 Transact-SQL 批处理的第一个可能结果集的元数据。 如果批处理没有返回结果,则返回一个空的结果集。 如果数据库引擎无法确定将通过执行静态分析来执行的第一个查询的元数据,则引发错误。 动态管理视图 sys.dm_exec_describe_first_result_set (Transact-SQL) 返回相同的信息。
适用范围:SQL Server(SQL Server 2012 至当前版本),Windows Azure SQL Database(初始版本至当前版本)。 |
语法
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 NOT NULL |
指示列是出于浏览信息目的而额外添加的列,该列不会实际显示在结果集中。 |
column_ordinal |
int NOT NULL |
在结果集中包含列的序号位置。 第一列的位置将指定为 1。 |
name |
sysname NULL |
包含列的名称(如果可以确定名称)。 否则,它将包含 NULL。 |
is_nullable |
bit NOT 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 NOT NULL |
列的最大长度(字节)。 -1 = 列数据类型为 varchar(max)、nvarchar(max)、varbinary(max) 或 xml。 对于 text 列,max_length 值为 16 或 sp_tableoption 'text in row' 设置的值。 |
precision |
tinyint NOT NULL |
如果为基于数值的列,则为该列的精度。 否则,返回 0。 |
scale |
tinyint NOT 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 NOT NULL |
如果返回的数据类型为 XML,并且保证该类型是完整的 XML 文档(包含根节点,与 XML 片段相对),则返回 1。 否则,返回 0。 |
is_case_sensitive |
bit NOT NULL |
如果列为区分大小写的字符串类型,则返回 1;否则为 0。 |
is_fixed_length_clr_type |
bit NOT 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)
权限
要求具有执行 @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 |
问题示例
下面的示例对所有示例使用两个表。 请执行以下语句以创建示例表。
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;'
结果:varchar(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.;'
结果:int NULL
某些代码路径不返回任何结果
第一次结果集是 Null 或结果集。
sp_describe_first_result_set @tsql =
N'
IF(1=1)
RETURN;
SELECT a FROM t1;'
结果:int NULL
动态 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 的另一个用户在具有列的默认架构 s1 中具有名为 t1 的表(int NOT NULL)。
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)