Insérer / mettre à jour en fonction du code XML dynamic

J'ai le XML suivant:

<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> 

J'essaye d'écrire une requête qui inserta un nouvel logging ou mettra à jour un existant basé sur xml donné. Le problème est que je ne peux pas utiliser des noms prédéfinis de colonnes, car la structure de la table change parfois. L'idée est donc de générer une requête dynamic et de l'appliquer. Jusqu'à présent, j'ai la chose suivante:

  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 

S'il y a une meilleure façon d'get cela en SQL, je voudrais savoir, je sais que je peux le faire en dehors de SQL dans mon code d'application, mais je voudrais l'avoir en un seul endroit dans la procédure stockée pour fournir xml et ont requirejs action prise.

MISE À JOUR 1

Je voudrais clarifier que mon problème principal est la génération de requête appropriée basée sur XML. La façon différente de gérer instert / update est agréable à voir, mais en plus

MISE À JOUR 2

Il peut y avoir plus d'une table en XML. Par exemple non seulement des données mais aussi des données2

MISE À JOUR 3

J'ai mis à jour ce que j'ai maintenant – et il génère maintenant une insertion / mise à jour correcte mais j'ai maintenant des problèmes avec la conversion. Par exemple, la string de date est au format XML et SQL ne veut pas la convertir automatiquement. Donc, ma prochaine étape est d'get le type de colonne approprié à partir de la database et au lieu de générer des requêtes directement depuis xml.J'espère que cela fonctionnera.

Oui.

Vous pouvez utiliser MERGE et SQL XQuery pour le faire en une seule instruction.

Quelque chose comme…

 merge Data as target using ( select xqvalue('Id[1]','uniqueidentifier') as ID, xqvalue('Number[1]','varchar(50)') as Number, xqvalue('Location[1]','varchar(50)') as Town, xqvalue('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);