0

ストアド プロシージャに渡されたパラメータをクエリし、パラメータの文字列を作成せずに XML として返し、それを xml としてキャストする方法はありますか? 毎回物理的にコーディングする必要なく、ほとんどの SP で機能する一般的なものを探していますか?

ベリファイ固有の情報にアクセスして変更する一連のストアド プロシージャがあります。SP の最後に、SP の名前と、SP の呼び出しに使用されたパラメーター (xml 形式) をログ テーブルに挿入します。SP の名前を取得する方法と、SP のパラメーターのリストを取得する方法を知っています。私が欲しいのは、渡されたパラメーターの実際の値に沿って、すべてを XML にマッシュアップする方法です。

各パラメーターを手動でコーディングせずに、これを行うものを探しています:

DECLARE @L_Data varchar(1500)
SET @L_Data = '<parms>' + 
CASE WHEN @ParamRegStationID IS NULL THEN ''
ELSE ',@ParamRegStationID=''' + Convert(varchar, @ParamRegStationID) + '''' END +
CASE WHEN @ParamScheduleID IS NULL THEN '' 
ELSE ',@ParamScheduleID=''' + Convert(varchar, @ParamScheduleID) + '''' END +
CASE WHEN @ParamPatientID IS NULL THEN '' 
ELSE ',@ParamPatientID=''' + Convert(varchar, @ParamPatientID) + '''' END +
CASE WHEN @ParamHISPatientID IS NULL THEN '' 
ELSE ',@ParamHISPatientID=''' + @ParamHISPatientID + '''' END +
CASE WHEN @ParamEvent IS NULL THEN '' 
ELSE ',@ParamEvent=''' + @ParamEvent + '''' END +
'</parms>'

これは機能せず、私が望んでいるほどエレガントではありません。ただし、これは私が最終的に到達しようとしていることを示す例です。一時テーブルを作成しますが、パラメーターを列として追加しないため、後で XML として抽出できます。

    ALTER PROC uspTest
    @ParamID as bigint=null,
    @ParamXYZ as varchar(255)=null
as

-- PROC Does whatever it is going to do ....

DECLARE @ProcName varchar(128), @ParmName varchar(128), @ParmType varchar(128), @ParmLen int, 
@ParmSQL varchar(1000)
select @ProcName=OBJECT_NAME(@@PROCID)
--select * from INFORMATION_SCHEMA.ROUTINES where ROUTINE_TYPE='PROCEDURE' and ROUTINE_NAME=@ProcName
DECLARE csrParms CURSOR
FOR 
select PARAMETER_NAME, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH from INFORMATION_SCHEMA.PARAMETERS where SPECIFIC_NAME=@ProcName and PARAMETER_MODE='IN' 
ORDER BY ORDINAL_POSITION
FOR READ ONLY

OPEN csrParms
FETCH NEXT FROM csrParms
INTO @ParmName, @ParmType, @ParmLen

CREATE TABLE #Parms(ID int identity(1,1), Created DateTime)
INSERT INTO #Parms select GETDATE()

WHILE @@FETCH_STATUS = 0
BEGIN
-- GET Parm value and format as xml attribute to save parm
SET @ParmSQL = 'ALTER TABLE #Parms add ' + @ParmName + ' varchar(' + CAST(ISNULL(@ParmLen, 128) as varchar(128)) + ') NULL '
print @ParmSQL
EXEC (@ParmSQL)
SET @ParmSQL = 'UPDATE #Parms SET ' + @ParmName + ' = ''????''' 
print @ParmSQL
--EXEC (@ParmSQL)
FETCH NEXT FROM csrParms
INTO @ParmName, @ParmType, @ParmLen
END

SET @ParmSQL = CAST((select * from #Parms FOR XML RAW) as varchar(1000))
select @ParmSQL

CLOSE csrParms
DEALLOCATE csrParms

これは私が探しているものに近いです。??? を置き換える方法を知る必要があります。ただし、パラメーターの現在の値を動的に使用します。

    ALTER PROC uspTest
    @ParamID as bigint=null,
    @ParamXYZ as varchar(255)=null
as

-- PROC Does whatever it is going to do ....

DECLARE @ProcName varchar(128), @ParmName varchar(128), @ParmType varchar(128), @ParmLen int, 
@ParmSQL varchar(1000)
select @ProcName=OBJECT_NAME(@@PROCID)
--select * from INFORMATION_SCHEMA.ROUTINES where ROUTINE_TYPE='PROCEDURE' and ROUTINE_NAME=@ProcName
set @ParmSQL = 
'    CREATE TABLE #Parms(ID int identity(1,1), Created DateTime, ' + 
    STUFF((select (', ' + REPLACE(PARAMETER_NAME,'@','') + ' varchar(' + CAST(ISNULL(CHARACTER_MAXIMUM_LENGTH, 128) as varchar(128)) + ') NULL ')
     from INFORMATION_SCHEMA.PARAMETERS where SPECIFIC_NAME='uspTest' and PARAMETER_MODE='IN' 
     order by ORDINAL_POSITION for XML path(''), type).value('.', 'varchar(max)'), 1, 2, '')
+ '); 
' + 'INSERT INTO #Parms (Created) select GETDATE(); ' + STUFF((select ('; 
UPDATE #Parms SET ' + REPLACE(PARAMETER_NAME,'@','') + ' = ''???''')
     from INFORMATION_SCHEMA.PARAMETERS where SPECIFIC_NAME='uspTest' and PARAMETER_MODE='IN' 
     order by ORDINAL_POSITION for XML path(''), type).value('.', 'varchar(max)'), 1, 2, '')
+ '; 
select CAST((select * from #Parms FOR XML RAW) as varchar(1000));'

print @ParmSQL
EXEC (@ParmSQL)

次のようにprocを実行すると:

EXEC uspTest 1, 'test'

戻り値:

<row ID="1" Created="2012-04-20T09:44:43.700" ParamID="???" ParamXYZ="???"/>

プリントアウト:

CREATE TABLE #Parms(ID int identity(1,1), Created DateTime, ParamID varchar(128) NULL , ParamXYZ varchar(255) NULL ); 
INSERT INTO #Parms (Created) select GETDATE(); 
UPDATE #Parms SET ParamID = '???'; 
UPDATE #Parms SET ParamXYZ = '???'; 
select CAST((select * from #Parms FOR XML RAW) as varchar(1000));
4

1 に答える 1

1

これはSQLServer2000以降ですか?その場合、FORXML句を使用できます。

DECLARE @p1 varchar(100) = 'blah'
    , @p2 int = 1
    , @p3 datetime2(7) = '2011-01-01 13:41'
    ;

SELECT @p1 StringParm
    , @p2 IntParm
    , @p3 DateParm
FOR XML RAW

戻り値:

<row StringParm="blah" IntParm="1" DateParm="2011-01-01T13:41:00"/>

編集

ああ、そこにある問題は、パラメータリストと値(ローカル)を動的SQL(スコープ外になる)に解析する必要があるということです。

INFORMATION_SCHEMA.PARAMETERSを使用してパラメーターを動的にリストし、dbcc_inputbuffersを使用して実際の値を取得できると思います。何かのようなもの:

create procedure junk
    (   @int INT 
        , @string VARCHAR(20) 
        , @date DATE 
    )
AS 
BEGIN
    DECLARE @tmp TABLE
        (   EventType NVARCHAR(30)
            , PARMS INT
            , Info NVARCHAR(2000)
        );

    DECLARE @object NVARCHAR(200);

    INSERT INTO @tmp
    EXEC('DBCC INPUTBUFFER(@@SPID) WITH NO_INFOMSGS');

    SELECT INFO
        , 'Call' lType
    FROM @tmp
    UNION 
    SELECT STUFF(
        (   SELECT ', ' + parameter_name
            FROM INFORMATION_SCHEMA.PARAMETERS 
            WHERE SPECIFIC_NAME = OBJECT_NAME(@@procid)
            ORDER BY ORDINAL_POSITION
            FOR XML PATH('')
        )
        , 1
        , 2
        , ''
        )
        , 'Parms';
END

これで、次のようになります。

exec dbo.junk  @int = 3, @string = 'hoo', @date = '2/2/2002';

戻り値:

exec dbo.junk  @int = 3, @string = 'hoo', @date = '2/2/2002';   Call
@int, @string, @date                                                 Parms

それはあなたに道を開くはずです。トリッキーな点は、DBCC_INPUTBUFFERSが正確な呼び出し文字列を返すことです。したがって、入力行をパラメーターリストに一致させるために、呼び出しを解析するコードを記述する必要があります。そのルートを使用する場合は、解析を実行するストアド関数が必要になる可能性があります。上記の戻り値のような呼び出し文字列とパラメータリストを取得し、それらを照合し、FORXML句を使用して必要な形式を返す可能性があります。

パラメータリストに関連付けられたカーソルで呼び出し文字列を解析することもできます。次に、パラメーターを順番にプルして、コンマと@を探します。それを考慮しなかった場合、それらの文字を含むパラメーター値で問題が発生する可能性があります。

私見ですが、関数ヘッダーからほとんどコピー/貼り付けできる単純な選択と比較すると、それを二乗するのは大変な作業のようです。もちろん、大量の手順について話している場合は、それだけの価値があるかもしれません。いずれにせよ、幸運と考えさせられる質問に感謝します。

于 2012-04-19T23:10:16.477 に答える