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

ストアドプロシージャの列名とタイプを取得しますか?

    [以前にこの質問に答えたことがあることに気づきました]

    ストアドプロシージャに対してこれを行うことは、ビューやテーブルの場合よりもはるかに複雑です。問題の1つは、ストアドプロシージャが、入力パラメータや、サーバーの状態や時刻など、制御できないものに応じて、複数の異なるコードパスを持つ可能性があることです。たとえば、このストアドプロシージャ?条件に関係なく複数の結果セットがある場合はどうなりますか?

    CREATE PROCEDURE dbo.foo
      @bar INT
    AS
    BEGIN
      SET NOCOUNT ON;
    
      IF @bar = 1
        SELECT a, b, c FROM dbo.blat;
      ELSE
        SELECT d, e, f, g, h FROM dbo.splunge;
    END
    GO
    

    ストアドプロシージャにコードパスがなく、常に同じ結果セットが表示されると確信している場合(および、ストアドプロシージャにオプション以外のパラメータがある場合に提供する値を事前に決定できる場合)、簡単な例を見てみましょう。

    CREATE PROCEDURE dbo.bar
    AS
    BEGIN
      SET NOCOUNT ON;
    
      SELECT a = 'a', b = 1, c = GETDATE();
    END
    GO
    

    FMTONLY

    1つの方法は、次のようなことを行うことです。

    SET FMTONLY ON;
    GO
    EXEC dbo.bar;
    

    これにより、空の結果セットが提供され、クライアントアプリケーションはその結果セットのプロパティを調べて、列名とデータ型を判別できます。

    現在、SET FMTONLY ON;には多くの問題があります。 ここでは説明しませんが、少なくとも、このコマンドは非推奨になっていることに注意してください。これには正当な理由があります。また、SET FMTONLY OFF;にも注意してください。 完了したら、またはストアドプロシージャを正常に作成したのに、実行できないのはなぜか疑問に思うでしょう。いいえ、それは私に起こったばかりなので、私はあなたにそれについて警告していません。本音。 :-)

    OPENQUERY

    ループバックリンクサーバーを作成することで、OPENQUERYなどのツールを使用できます。 ストアドプロシージャを実行しますが、検査できる構成可能な結果セットを返します(非常に緩い定義として受け入れてください)。最初にループバックサーバーを作成します(これは、FOOという名前のローカルインスタンスを想定しています。 ):

    USE master;
    GO
    EXEC sp_addlinkedserver @server = N'.\FOO', @srvproduct=N'SQL Server'
    GO
    EXEC sp_serveroption @server=N'.\FOO', @optname=N'data access', 
      @optvalue=N'true';
    

    これで、上記の手順を実行して、次のようなクエリにフィードできます。

    SELECT * INTO #t 
    FROM OPENQUERY([.\FOO], 'EXEC dbname.dbo.bar;')
    WHERE 1 = 0;
    
    SELECT c.name, t.name
    FROM tempdb.sys.columns AS c
    INNER JOIN sys.types AS t
    ON c.system_type_id = t.system_type_id
    WHERE c.[object_id] = OBJECT_ID('tempdb..#t');
    

    これはエイリアスタイプ(以前はユーザー定義データタイプと呼ばれていました)を無視し、たとえばsysnameとして定義された列に2つの行を表示する場合もあります。 。しかし、上記から次のようになります:

    name   name
    ----   --------
    b      int
    c      datetime
    a      varchar
    

    明らかに、ここで行うべき作業は他にもあります-varchar 長さは表示されません。datetime2などの他のタイプの精度/スケールを取得する必要があります 、time およびdecimal 。しかし、それは始まりです。

    SQL Server 2012

    SQL Server 2012には、メタデータの検出をはるかに簡単にするいくつかの新機能があります。上記の手順では、次のことができます。

    SELECT name, system_type_name
    FROM sys.dm_exec_describe_first_result_set_for_object
    (
      OBJECT_ID('dbo.bar'), 
      NULL
    );
    

    とりわけ、これは実際に精度とスケールを提供し、エイリアスタイプを解決します。上記の手順の場合、これにより次のようになります。

    name   system_type_name
    ----   ----------------
    a      varchar(1)
    b      int
    c      datetime
    

    視覚的にはそれほど違いはありませんが、さまざまな精度とスケールですべての異なるデータ型を調べ始めると、この関数が追加の作業を行うことに感謝します。

    欠点:SQL Server 2012では、少なくともこれらの関数は最初のでのみ機能します。 結果セット(関数の名前が示すように)



    1. SQL ServerでのSIN()の例

    2. バージョン11のlocaldbの接続文字列は何ですか

    3. SELECTリストの他の場所でエイリアスを参照する

    4. テーブル定義を表示するT-SQLクエリ?