小编典典

使用临时表时,描述第一个结果集的SQL Server失败(sp_describe_first_result_set)

sql

长话短说,我有一个第三方应用程序,当它无法检索查询/存储过程的元数据时,其行为会有所不同。

众所周知,sys.sp_describe_first_result_set当使用临时表时,它无法检索存储过程的元数据。

为了简单起见,这是一个简单的示例。

CREATE PROCEDURE dbo.Test
    @Seed INT = 0
AS
BEGIN
    CREATE TABLE #MyTemp (
        ID INT NOT NULL
    );

    INSERT INTO #MyTemp (ID)
    VALUES
          (@Seed + 1)
        , (@Seed + 2)
        , (@Seed + 3)
    ;

    SELECT
        ID
    FROM
        #MyTemp
END

执行此SP将返回一个结果集,其中有一个列(ID)和三个记录。

EXEC dbo.Test
    @Seed = 1;

结果是:

ID
-----------
2
3
4

但是,尝试获取元数据将失败:

EXEC sys.sp_describe_first_result_set @tsql = N'EXEC dbo.Test @Seed = 1;';

结果是:

Msg 11526, Level 16, State 1, Procedure sp_describe_first_result_set, Line 1 [Batch Start Line 24]
The metadata could not be determined because statement 'INSERT INTO #MyTemp (ID)
    VALUES
          (@Seed + 1)
        , (@Seed + 2)
        , (@Seed + 3)' in procedure 'Test' uses a temp table.

(这是预料之中的,因为这是的已知限制sp_describe_first_result_set

问题是,当我们的第三方应用程序遇到此错误时,它将执行两次SP(首先分析结果集并创建一个临时表,然后执行一次INSERT .. EXEC将数据加载到它创建的临时表中)。

当元数据可用时,它将使用获取元数据,sys.sp_describe_first_result_set并使用该信息创建临时表。

由于我们在2012版以下没有任何SQL Server,因此可以使用该WITH RESULT SETS子句,但是在上述应用中无法对其进行配置或手动提供元数据信息。

如何使元数据可用于使用此SP的应用程序?

我在回答中提供了两种解决方案,但我想知道是否有我不知道的一种解决方案。


阅读 264

收藏
2021-05-23

共1个答案

小编典典

我当前的解决方案是创建一个包装器存储过程,该过程执行现有的包装器过程,并传递所有参数,但定义结果集的元数据。

继续问题中的示例:

EXEC sp_rename 'dbo.Test', 'Test_Logic', 'OBJECT';
GO

CREATE PROCEDURE dbo.Test
    @Seed INT = 0
AS
BEGIN
    EXEC dbo.Test_Logic
        @Seed = @Seed
    WITH RESULT SETS (
        (
            ID INT
        )
    )
    ;
END

现在,如果我尝试获取元数据,则可以获取它:

EXEC sys.sp_describe_first_result_set @tsql = N'EXEC dbo.Test @Seed = 1;';

结果是:

is_hidden column_ordinal name                                                                                                                             is_nullable system_type_id system_type_name                                                                                                                 max_length precision scale collation_name                                                                                                                   user_type_id user_type_database                                                                                                               user_type_schema                                                                                                                 user_type_name                                                                                                                   assembly_qualified_type_name                                                                                                                                                                                                                                     xml_collection_id xml_collection_database                                                                                                          xml_collection_schema                                                                                                            xml_collection_name                                                                                                              is_xml_document is_case_sensitive is_fixed_length_clr_type source_server                                                                                                                    source_database                                                                                                                  source_schema                                                                                                                    source_table                                                                                                                     source_column                                                                                                                    is_identity_column is_part_of_unique_key is_updateable is_computed_column is_sparse_column_set ordinal_in_order_by_list order_by_is_descending order_by_list_length tds_type_id tds_length  tds_collation_id tds_collation_sort_id
--------- -------------- -------------------------------------------------------------------------------------------------------------------------------- ----------- -------------- -------------------------------------------------------------------------------------------------------------------------------- ---------- --------- ----- -------------------------------------------------------------------------------------------------------------------------------- ------------ -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- --------------- ----------------- ------------------------ -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- ------------------ --------------------- ------------- ------------------ -------------------- ------------------------ ---------------------- -------------------- ----------- ----------- ---------------- ---------------------
0         1              ID                                                                                                                               1           56             int                                                                                                                              4          10        0     NULL                                                                                                                             NULL         NULL                                                                                                                             NULL                                                                                                                             NULL                                                                                                                             NULL                                                                                                                                                                                                                                                             NULL              NULL                                                                                                                             NULL                                                                                                                             NULL                                                                                                                             0               0                 0                        NULL                                                                                                                             NULL                                                                                                                             NULL                                                                                                                             NULL                                                                                                                             NULL                                                                                                                             NULL               NULL                  NULL          NULL               NULL                 NULL                     NULL                   NULL                 38          4           NULL             NULL

(在这里看起来很糟糕,但是有效)

缺点是,现在我必须维护两个SP,并且需要执行后续的SP。

替代解决方案

一种替代解决方案是使用动态sql并sys.sp_executesql与该WITH RESULT SETS子句一起运行它。

这样做的主要缺点是,SQL Server和VisualStudio(数据库项目)无法跟踪动态SQL中的依赖关系。

看起来像这样:

ALTER PROCEDURE dbo.Test
    @Seed INT = 0
AS
BEGIN
    CREATE TABLE #MyTemp (
        ID INT NOT NULL
    );

    INSERT INTO #MyTemp (ID)
    VALUES
          (@Seed + 1)
        , (@Seed + 2)
        , (@Seed + 3)
    ;


    DECLARE @STMT NVARCHAR(MAX) = N'
SELECT
    ID
FROM
    #MyTemp
;';

    EXEC sys.sp_executesql
        @stmt = @STMT
    WITH RESULT SETS (
        (
            ID INT
        )
    )
END

当然,我认为SP越复杂,就越难维护动态SQL,因此我更喜欢第一个解决方案。

2021-05-23