sp_describe_first_result_set (Transact-SQL)
適用於:SQL Server Azure SQL 資料庫 Azure SQL 受控執行個體 Azure Synapse Analytics Analytics Platform System (PDW) Microsoft Fabric 的 SQL 端點分析 Microsoft Fabric 的倉儲
傳回 Transact-SQL 批次第一個可能結果集的元數據。 如果批次未傳回任何結果,則傳回空的結果集。 如果 資料庫引擎 無法透過執行靜態分析來判斷第一個查詢的元數據,就會引發錯誤。 動態管理檢視 sys.dm_exec_describe_first_result_set 會傳回相同的資訊。
語法
sp_describe_first_result_set [ @tsql = ] N'tsql'
[ , [ @params = ] N'@parameter_name data_type [ , ... n ]' ]
[ , [ @browse_information_mode = ] <tinyint> ]
[ ; ]
引數
[ @tsql = ] 'tsql'
一或多個 Transact-SQL 語句。 @tsql可能是 nvarchar(n) 或 nvarchar(max)。
[ @params = ] N'@parameter_name data_type [ , ... n ]'
@params提供 Transact-SQL 批次參數的宣告字串,其類似於 sp_executesql
。 參數可能是 nvarchar(n) 或 nvarchar(max)。
字串,包含內嵌在 @tsql 中之所有參數的定義。 字串必須是 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,則傳回狀態會以 的 error_type sys.dm_exec_describe_first_result_set
數據行中所述的錯誤類型填入。 如果從 Transact-SQL 呼叫程式,即使發生錯誤,傳回值一律為零。
結果集
這個常見的元數據會以結果集的形式傳回,結果元數據中每個數據行各有一個數據列。 每個數據列都會以下一節中所述的格式描述數據行的類型和 Null 性。 如果每個控件路徑沒有第一個語句,則會傳回含有零個數據列的結果集。
資料行名稱 | 資料類型 | 描述 |
---|---|---|
is_hidden |
bit | 表示數據行是為了瀏覽資訊而新增的額外數據行,而且實際上不會出現在結果集中。 不可為 Null。 |
column_ordinal |
int | 包含結果集中數據行的序數位置。 第一個資料列的位置會指定為 1 。 不可為 Null。 |
name |
sysname | 如果可以判斷名稱,則包含數據行的名稱。 否則,它會包含 NULL 。 可為 Null。 |
is_nullable |
bit | 如果資料列允許 NULL ,則包含值1 ,0 如果資料行不允許 NULL ,而且1 如果無法判斷資料行是否允許NULL ,則為 。 不可為 Null。 |
system_type_id |
int | 包含 system_type_id 資料行的 數據類型,如 中所 sys.types 指定。 如果是 CLR 型別,即使資料 system_type_name 行傳 NULL 回 ,這個資料行也會傳回 值 240 。 不可為 Null。 |
system_type_name |
nvarchar(256) | 包含為數據行數據類型指定的名稱和自變數(例如長度、有效位數、小數字數)。 如果數據類型是使用者定義的別名類型,則會在這裡指定基礎系統類型。 如果是CLR使用者定義類型, NULL 則會在此數據行中傳回。 可為 Null。 |
max_length |
smallint | 數據行的最大長度(以位元組為單位)。-1 = 數據行數據類型為 varchar(max)、 nvarchar(max)、 varbinary(max)或 xml。如果是 文字數據 行,此值 max_length 為 16 或 所 sp_tableoption 'text in row' 設定的值。 不可為 Null。 |
precision |
tinyint | 如果以數值為基礎,則為數據行的有效位數。 否則傳回 0 。 不可為 Null。 |
scale |
tinyint | 如果以數值為基礎,則為數據行小數字數。 否則傳回 0 。 不可為 Null。 |
collation_name |
sysname | 如果以字元為基礎,則為數據行定序的名稱。 否則傳回 NULL 。 可為 Null。 |
user_type_id |
int | 針對 CLR 和別名類型,包含 user_type_id 資料行的數據類型,如 中所 sys.types 指定。 否則為 NULL 。 可為 Null。 |
user_type_database |
sysname | 針對 CLR 和別名類型,包含定義型別的資料庫名稱。 否則為 NULL 。 可為 Null。 |
user_type_schema |
sysname | 針對 CLR 和別名類型,包含定義型別的架構名稱。 否則為 NULL 。 可為 Null。 |
user_type_name |
sysname | 針對 CLR 和別名類型,包含類型的名稱。 否則為 NULL 。 可為 Null。 |
assembly_qualified_type_name |
nvarchar(4000) | 針對 CLR 類型,傳回定義型別的元件和類別名稱。 否則為 NULL 。 可為 Null。 |
xml_collection_id |
int | 包含 xml_collection_id 資料行的 數據類型,如 中所 sys.columns 指定。 如果傳回的類型與 XML 架構集合沒有關聯,則此數據行會 NULL 傳回。 可為 Null。 |
xml_collection_database |
sysname | 包含定義與這個類型相關聯之 XML 架構集合的資料庫。 如果傳回的類型與 XML 架構集合沒有關聯,則此數據行會 NULL 傳回。 可為 Null。 |
xml_collection_schema |
sysname | 包含定義與這個類型相關聯之 XML 架構集合的架構。 如果傳回的類型與 XML 架構集合沒有關聯,則此數據行會 NULL 傳回。 可為 Null。 |
xml_collection_name |
sysname | 包含與此類型相關聯的 XML 架構集合名稱。 如果傳回的類型與 XML 架構集合沒有關聯,則此數據行會 NULL 傳回。 可為 Null。 |
is_xml_document |
bit | 1 如果傳回的數據類型是 XML,而且該類型保證是完整的 XML 檔(包括根節點),而不是 XML 片段,則傳回 。 否則傳回 0 。 不可為 Null。 |
is_case_sensitive |
bit | 1 如果資料列是區分大小寫的字串類型,如果0 不是,則傳回 。 不可為 Null。 |
is_fixed_length_clr_type |
bit | 1 如果資料列是固定長度的 CLR 型別,如果0 不是,則傳回 。 不可為 Null。 |
source_server |
sysname | 此結果中數據行所傳回之源伺服器的名稱(如果它源自遠端伺服器)。 名稱會在 中 sys.servers 出現時提供。 NULL 如果資料列源自本地伺服器,或無法判斷來源的伺服器,則傳回 。 只有在要求瀏覽資訊時才會填入。 可為 Null。 |
source_database |
sysname | 此結果中數據行所傳回之原始資料庫的名稱。 如果無法判斷資料庫,則傳 NULL 回 。 只有在要求瀏覽資訊時才會填入。 可為 Null。 |
source_schema |
sysname | 此結果中數據行所傳回之原始架構的名稱。 如果無法判斷架構,則傳 NULL 回 。 只有在要求瀏覽資訊時才會填入。 可為 Null。 |
source_table |
sysname | 此結果中數據行所傳回之原始數據表的名稱。 如果無法判斷資料表,則傳 NULL 回 。 只有在要求瀏覽資訊時才會填入。 可為 Null。 |
source_column |
sysname | 結果數據行所傳回之原始數據行的名稱。 如果無法判斷資料列,則傳 NULL 回 。 只有在要求瀏覽資訊時才會填入。 可為 Null。 |
is_identity_column |
bit | 1 如果資料列是識別列,則0 傳回 ,如果不是,則傳回 。 NULL 如果無法判斷資料列是識別列,則傳回 。 可為 Null。 |
is_part_of_unique_key |
bit | 如果資料列是唯一索引的一部分,則傳 1 回 ,如果不是, 0 則傳回 。 NULL 如果無法判斷資料列是唯一索引的一部分,則傳回 。 只有在要求瀏覽資訊時才會填入。 可為 Null。 |
is_updateable |
bit | 1 如果資料列是可更新的,則0 傳回 ,如果不是,則傳回 。 NULL 如果無法判斷資料列可更新,則傳回 。 可為 Null。 |
is_computed_column |
bit | 1 如果資料列是計算資料列,則0 傳回 ,如果不是,則傳回 。 NULL 如果無法判斷資料列是計算資料列,則傳回 。 可為 Null。 |
is_sparse_column_set |
bit | 1 如果資料列是疏鬆資料列,則0 傳回 ,如果不是,則傳回 。 如果無法判斷資料列是疏鬆資料列集的一部分,則傳 NULL 回 。 可為 Null。 |
ordinal_in_order_by_list |
smallint | 此資料列在 ORDER BY 清單中的位置。 NULL 如果資料列未出現在ORDER BY 清單中,或無法唯一判斷清單,ORDER BY 則傳回 。 可為 Null。 |
order_by_list_length |
smallint | 清單的 ORDER BY 長度。 NULL 如果沒有ORDER BY 清單,或清單無法唯一決定,ORDER BY 則傳回 。 針對 所 sp_describe_first_result_set 傳回的所有數據列,這個值都相同。 可為 Null。 |
order_by_is_descending |
smallint | ordinal_in_order_by_list 如果 不是 NULL ,則數據order_by_is_descending 行會報告這個數據行的 ORDER BY 子句方向。 否則會報告 NULL 。 可為 Null。 |
tds_type_id |
int | 供內部使用。 不可為 Null。 |
tds_length |
int | 供內部使用。 不可為 Null。 |
tds_collation_id |
int | 供內部使用。 可為 Null。 |
tds_collation_sort_id |
tinyint | 供內部使用。 可為 Null。 |
備註
sp_describe_first_result_set
保證如果程式傳回第一個結果集元數據(假設的)批次 A,然後執行該批次(A),則批次:
- 引發優化時間錯誤
- 引發運行時錯誤
- 不會傳回任何結果集
- 傳回具有所描述相同元數據的第一個結果集
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
、、 WHILE
ELSE
/IF
和 Transact-SQL 區塊)以及任何程式、動態 Transact-SQL/TRY
CATCH
批次,或語句從輸入批次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' > 。
- nvarchar(a) 至 nvarchar(max)
- varbinary(a) 至 varbinary(a') 其中 a' > 。
- varbinary(a) 至 varbinary(max)
sp_describe_first_result_set
不支援間接遞歸。
權限
需要許可權才能執行 @tsql 自變數。
範例
一般範例
A. 基本範例
下列範例說明從單一查詢傳回的結果集。
EXEC sp_describe_first_result_set @tsql = N'SELECT object_id, name, type_desc FROM sys.indexes';
下列範例顯示從包含參數的單一查詢傳回的結果集。
EXEC 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 INTO #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
);
錯誤,因為資料行數目不同
此範例中可能第一個結果集中的數據行數目不同。
EXEC 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.';
錯誤,因為數據類型不同
數據行類型在不同的可能第一個結果集中有所不同。
EXEC sp_describe_first_result_set @tsql = N'
IF (1 = 1)
SELECT a FROM t1;
ELSE
SELECT a FROM t2;';
這會導致類型不符的錯誤(int 與 smallint)。
無法判斷數據行名稱
可能第一個結果集中的數據行會因相同可變長度類型、可為 Null 和數據行名稱而有所不同:
EXEC sp_describe_first_result_set @tsql = N'
IF (1 = 1)
SELECT b FROM t1;
ELSE
SELECT d FROM t2;';
以下為部分結果集。
資料行 | 值 |
---|---|
name |
未知的數據行名稱 |
system_type_name |
varchar |
max_length |
20 |
is_nullable |
1 |
強制透過別名相同的數據行名稱
與先前相同,但數據行透過數據行別名具有相同的名稱。
EXEC sp_describe_first_result_set @tsql = N'
IF (1 = 1)
SELECT b FROM t1;
ELSE
SELECT d AS b FROM t2;';
以下為部分結果集。
資料行 | 值 |
---|---|
name |
b |
system_type_name |
varchar |
max_length |
20 |
is_nullable |
1 |
錯誤,因為無法比對數據行類型
數據行類型在不同的可能第一個結果集中有所不同。
EXEC sp_describe_first_result_set @tsql = N'
IF (1 = 1)
SELECT b FROM t1;
ELSE
SELECT c FROM t1;';
這會導致類型不符的錯誤(varchar(10) 與 nvarchar(10))。
結果集可以傳回錯誤
第一個結果集是錯誤或結果集。
EXEC 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.';
以下為部分結果集。
資料行 | 值 |
---|---|
name |
a |
system_type_name |
int |
is_nullable |
1 |
某些程式代碼路徑不會傳回任何結果
第一個結果集是 Null 或結果集。
EXEC sp_describe_first_result_set @tsql = N'
IF (1 = 1)
RETURN;
SELECT a FROM t1;';
以下為部分結果集。
資料行 | 值 |
---|---|
name |
a |
system_type_name |
int |
is_nullable |
1 |
動態 SQL 的結果
第一個結果集是可探索的動態 SQL,因為它是常值字串。
EXEC sp_describe_first_result_set @tsql = N'
EXEC(N''SELECT a FROM t1'');';
以下為部分結果集。
資料行 | 值 |
---|---|
name |
a |
system_type_name |
int |
is_nullable |
1 |
動態 SQL 的結果失敗
第一個結果集因為動態 SQL 而未定義。
EXEC 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,所以無法探索結果。
使用者指定的結果集
用戶手動指定第一個結果集。
EXEC 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)
);';
以下為部分結果集。
資料行 | 值 |
---|---|
name |
Column1 |
system_type_name |
bigint |
is_nullable |
0 |
模棱兩可的結果集所造成的錯誤
此範例假設另一位名為 user1
的用戶在默認架構s1
中具有名為 t1
的數據表,且具有數據行 (a int NOT NULL
)。
EXEC sp_describe_first_result_set @tsql = N'
IF (@p > 0)
EXECUTE AS USER = ''user1'';
SELECT * FROM t1;',
@params = N'@p int';
此程式代碼會導致 Invalid object name
錯誤。 t1
可以是 dbo.t1
或 s1.t1
,每一個都有不同數目的數據行。
結果,即使結果集模棱兩可
使用與上一個範例相同的假設。
EXEC sp_describe_first_result_set @tsql =
N'
IF (@p > 0)
EXECUTE AS USER = ''user1'';
SELECT a FROM t1;';
以下為部分結果集。
資料行 | 值 |
---|---|
name |
a |
system_type_name |
int |
is_nullable |
1 |
和 s1.t1.a
都有 dbo.t1.a
int 類型,以及不同的可為 Null 性。