2

私は次のXMLを持っています:

<NewDataSet>
  <Data>
    <Id>560f05b2-b215-4fea-9ac6-7f012fbca331</Id>   
    <Number>384D25334E04593B6DE9955E72F413F8A0A828FF</Number>
    <CurrentDate>2012-11-21T09:09:26+00:00</CurrentDate>
  </Data>
  <Data>
    <Id>9cff574b-59ea-4cbd-a2db-9ed02b6cc602</Id>  
    <Number>384D25334E04593B6DE9955E72F413F8A0A828FF</Number>
    <Location>Town</Location>
    <CurrentDate>2012-11-21T09:09:53+00:00</CurrentDate>
  </Data> 
</NewDataSet>

指定されたxmlに基づいて、新しいレコードを挿入したり、既存のレコードを更新したりするクエリを作成しようとしています。問題は、テーブルの構造が変更されることがあるため、事前定義された列の名前を使用できないことです。したがって、アイデアは動的クエリを生成して適用することです。これまでのところ、私は次のことを持っています:

    SET NOCOUNT OFF;


    DECLARE @TableName nvarchar(50)
    DECLARE @TableData xml
    DECLARE @Query nvarchar(max)
    DECLARE @Id uniqueidentifier
    DECLARE @CurrentDate datetime

    -- declare cursor
    DECLARE cursor_inserting CURSOR LOCAL FAST_FORWARD FOR
    SELECT 
        r.value('fn:local-name(.)', 'nvarchar(50)'), 
        r.query('.')
    FROM @Data.nodes('//NewDataSet/*') AS records(r)
    ORDER BY r.value('fn:local-name(.)', 'nvarchar(50)')

    -- open cursor
    OPEN cursor_inserting
    FETCH NEXT FROM cursor_inserting INTO @TableName, @TableData

    WHILE @@FETCH_STATUS = 0
    BEGIN

        -- Get id
        SELECT @Id = o.value('Id[1]', 'uniqueidentifier') FROM @TableData.nodes('*') as n(o)
        SELECT @CurrentDate = o.value('CurrentDate[1]', 'datetime') FROM @TableData.nodes('*') as n(o)

        SET @Query = NULL

-- temporary update query
SET @UpdateTemp = NULL
SELECT @UpdateTemp = COALESCE(@UpdateTemp + ', ', '') + o.value('fn:local-name(.)', 'nvarchar(50)') + ' = ''' + CAST(o.query('text()') as nvarchar(4000)) + '''' FROM @TableData.nodes('/*/*') as n(o)
SET @UpdateTemp = 'UPDATE ' + @TableName + ' SET ' + @UpdateTemp + ' WHERE Id = ''' + CAST(@Id as nvarchar(40)) + ''''

-- temporary insert query
SET @Insert1Temp = NULL
SELECT @Insert1Temp = COALESCE(@Insert1Temp + ', ', '') + o.value('fn:local-name(.)', 'nvarchar(50)')  FROM @TableData.nodes('/*/*') as n(o)

SET @Insert2Temp = NULL
SELECT @Insert2Temp = COALESCE(@Insert2Temp + ', ', '') + '''' + CAST(o.query('text()') as nvarchar(4000)) + ''''  FROM @TableData.nodes('/*/*') as n(o)

SET @InsertTemp = 'INSERT INTO ' + @TableName  + ' ( ' + @Insert1Temp + ' ) VALUES ( ' + @Insert2Temp + ' )'

IF @TableName = 'Data'
BEGIN

    IF EXISTS (SELECT * FROM Data WHERE Id = @Id)
    BEGIN

        IF EXISTS (SELECT * FROM tblAudit WHERE Id = @Id AND CurrentDate < @CurrentDate)
        BEGIN               
            SET @Query = @UpdateTemp            
        END

    END
    ELSE
    BEGIN
        SET @Query = @InsertTemp
    END
END

IF @Query IS NOT NULL
BEGIN
    SELECT @Query
    EXEC (@Query)
END
        END
    FETCH NEXT FROM cursor_inserting INTO  @TableName, @TableData
END

CLOSE cursor_inserting
DEALLOCATE cursor_inserting

私が知りたいSQLの内部でこれを達成するためのより良い方法がある場合、アプリケーションコードでSQLの外部でこれを行うことができることを知っていますが、xmlを提供するためにストアドプロシージャの1つの場所にそれを置きたいと思っています。実行されたアクション。

更新1

私の主な問題は、XMLに基づくクエリの適切な生成であることを明確にしたいと思います。instert / updateを処理する別の方法は見た目が良いですが、追加として

更新2

xmlには複数のテーブルが存在する可能性があります。例:データだけでなくデータ2

更新3

私は今持っているものを更新しました-そしてそれは今適切な挿入/更新を生成していますが、私は今変換に問題があります。たとえば、日付文字列はxml形式であり、SQLはそれを自動的に変換することを望んでいません。したがって、次のステップは、データベースから適切な列タイプを取得し、xmlから直接クエリinstertを生成する代わりに、これが機能することを願っています。

4

1 に答える 1

1

はい。

MERGEおよびSQLXQueryを使用して、1つのステートメントでそれを行うことができます。

何かのようなもの...

merge Data as target
using 
(
    select  
        x.q.value('Id[1]','uniqueidentifier') as ID,
        x.q.value('Number[1]','varchar(50)') as Number,
        x.q.value('Location[1]','varchar(50)') as Town,
        x.q.value('CurrentDate[1]','datetime') as CurrentDate
    from
        @TableData.nodes('/NewDataSet/Data')x(q)
) as Source (ID,Number,Town,CurrentDate)
    on target.id=source.id
when matched and target.CurrentDate < source.CurrentDate then
    update set 
         Number = source.number, 
         town = source.town, 
         currentdate = source.currentdate
when not matched then
    insert (ID,number,town,currentdate)
    values (source.id,source.number,source.town,source.currentdate);    
于 2012-11-27T13:28:00.987 に答える