sql >> データベース >  >> RDS >> Sqlserver

ストアドプロシージャの結果セットの列定義を取得します

    したがって、tempdbにストアドプロシージャがあるとします。

    USE tempdb;
    GO
    
    CREATE PROCEDURE dbo.my_procedure
    AS
    BEGIN
        SET NOCOUNT ON;
    
        SELECT foo = 1, bar = 'tooth';
    END
    GO
    

    ストアドプロシージャが出力するメタデータを決定するための非常に複雑な方法があります。手順には単一の結果セットしか出力できないことや、データ型を正確に判別できない場合はデータ型について最善の推測が行われることなど、いくつかの注意点があります。 OPENQUERYを使用する必要があります 'DATA ACCESS'を使用したループバックリンクサーバー プロパティをtrueに設定します。 sys.serversをチェックして、有効なサーバーがすでにあるかどうかを確認できますが、手動でloopbackと呼ばれるサーバーを作成してみましょう。 :

    EXEC master..sp_addlinkedserver 
        @server = 'loopback',  
        @srvproduct = '',
        @provider = 'SQLNCLI',
        @datasrc = @@SERVERNAME;
    
    EXEC master..sp_serveroption 
        @server = 'loopback', 
        @optname = 'DATA ACCESS',
        @optvalue = 'TRUE';
    

    これをリンクサーバーとしてクエリできるようになったので、クエリの結果(ストアドプロシージャ呼び出しを含む)を通常のSELECTとして使用できます。 。したがって、これを行うことができます(データベースプレフィックスはであることに注意してください 重要です。そうしないと、エラー11529および2812が発生します):

    SELECT * FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');
    

    SELECT *を実行できる場合 、SELECT * INTOを実行することもできます :

    SELECT * INTO #tmp FROM OPENQUERY(loopback, 'EXEC tempdb.dbo.my_procedure;');
    

    そして、その#tmpテーブルが存在すると、次のように言ってメタデータを判別できます(SQL Server 2005以降を想定):

    SELECT c.name, [type] = t.name, c.max_length, c.[precision], c.scale
      FROM sys.columns AS c
      INNER JOIN sys.types AS t
      ON c.system_type_id = t.system_type_id
      AND c.user_type_id = t.user_type_id
      WHERE c.[object_id] = OBJECT_ID('tempdb..#tmp');
    

    (SQL Server 2000を使用している場合は、syscolumnsで同様のことを行うことができますが、同等のクエリを検証するのに便利な2000インスタンスがありません。)

    結果:

    name      type    max_length precision scale
    --------- ------- ---------- --------- -----
    foo       int              4        10     0
    bar       varchar          5         0     0
    

    デナリでは、これははるかに簡単になります。ここでも、最初の結果セットには制限がありますが、リンクサーバーをセットアップして、これらすべてのフープをジャンプする必要はありません。あなたはただ言うことができます:

    DECLARE @sql NVARCHAR(MAX) = N'EXEC tempdb.dbo.my_procedure;';
    
    SELECT name, system_type_name
        FROM sys.dm_exec_describe_first_result_set(@sql, NULL, 1);
    

    結果:

    name      system_type_name
    --------- ----------------
    foo       int             
    bar       varchar(5)      
    

    デナリまでは、袖をまくり上げて自分でデータ型を把握する方が簡単だと思います。上記の手順を実行するのが面倒であるだけでなく、エンジンが実行するデータ型が実行時間に基づいて推測するため、エンジンよりも正確な(または少なくともより正確な)推測を行う可能性がはるかに高いためです。可能な値のドメインに関する外部の知識がなくても、出力されます。この要素はデナリでも当てはまります。したがって、新しいメタデータ検出機能がすべてであるという印象を与えないでください。これらの機能により、上記の作業が少し面倒になります。

    ああ、そしてOPENQUERYでのその他の潜在的な落とし穴について 、ここでErland Sommarskogの記事を参照してください:

    http://www.sommarskog.se/share_data.html#OPENQUERY



    1. MySQLの最後の行を選択します

    2. 照合の競合を解決できません

    3. 'SELECT'ステートメントの'IF'-列の値に基づいて出力値を選択します

    4. SQL Serverでsp_dependsを使用しないでください(非推奨)