Tenho uma XML
variável contendo uma tabela. Esta tabela tem um número de colunas e uma linha. Nas duas primeiras colunas, preciso atualizar seus valores com o resultado de um procedimento armazenado - inserindo um valor se estiver vazio e atualizando o valor se ele já existir.
Isto é o que eu tenho até agora. Por favor, note que os nomes/estrutura dos elementos na tabela são verdadeiros para como eles serão na realidade (ou seja, todas as linhas são chamadas de "Linha" e todas as colunas são chamadas de "Coluna"). Isto é devido a uma restrição do programa que produz a tabela XML.
-- Declare xml variable. Either column could be empty or populated. They are shown empty here.
DECLARE @x xml = N'<?xml version="1.0" encoding="utf-16"?>
<Table>
<Row>
<Column></Column>
<Column></Column>
<Column>some data</Column>
<Column>some more data</Column>
</Row>
</Table>'
-- View xml table prior to modifications
SELECT tbl.col.value('Column[1]/text()[1]', 'int') 'id'
,tbl.col.value('Column[2]/text()[1]', 'datetime2(2)') 'date'
,tbl.col.value('Column[3]/text()[1]', 'varchar(50)') 'data'
,tbl.col.value('Column[4]/text()[1]', 'varchar(50)') 'more data'
FROM @x.nodes('//Table/Row') tbl(col)
-- Declare new id and date variables. This will come from a stored procedure. I've made it static to simplify the example.
DECLARE @id int = 24
DECLARE @date datetime2(2) = sysutcdatetime()
-- If id is empty, insert the id value. Otherwise, update the id value.
IF (SELECT tbl.col.value('Column[1]/text()[1]', 'int') 'id'
FROM @x.nodes('//Table/Row') tbl(col)) IS NULL
SET @x.modify('insert text{sql:variable("@id")} into (//Table/Row/Column)[1]')
ELSE
SET @x.modify('replace value of (//Table/Row/Column/text())[1] with sql:variable("@id")')
-- If date is empty, insert the date value. Otherwise, update the date value
IF (SELECT tbl.col.value('Column[2]/text()[1]', 'datetime2(2)') 'date'
FROM @x.nodes('//Table/Row') tbl(col)) IS NULL
SET @x.modify('insert text{sql:variable("@date")} into (//Table/Row/Column)[2]')
ELSE
SET @x.modify('replace value of (//Table/Row/Column/text())[2] with sql:variable("@date")')
-- View xml table after modifications
SELECT tbl.col.value('Column[1]/text()[1]', 'int') 'id'
,tbl.col.value('Column[2]/text()[1]', 'datetime2(2)') 'date'
,tbl.col.value('Column[3]/text()[1]', 'varchar(50)') 'data'
,tbl.col.value('Column[4]/text()[1]', 'varchar(50)') 'more data'
FROM @x.nodes('//Table/Row') tbl(col)
Isso parece funcionar; no entanto, estou pensando se há uma maneira de escrever a condição (ou seja, se estiver vazio, inserir; senão, substituir valor) dentro da própria função modify? Em outras palavras, posso evitar as IF...ELSE
instruções SQL e usar uma SET
instrução em vez disso?
Além disso, existe uma maneira de atualizar as duas colunas na mesma função de modificação ou isso precisa ser feito separadamente?
Desde já, obrigado!
EDIT Código de exemplo alterado para demonstrar que a tabela pode ter colunas adicionais e para esclarecer o formato da tabela XML.
Tente a seguinte solução aproveitando o SQL Server XQuery e sua expressão FLWOR.
Para este método, não importa se os valores XML existem ou não.
Meu entendimento é que seu exemplo XML é artificial, ou seja, os elementos XML são todos chamados Column . É por isso que no cenário da vida real você pode usar
local-name()
a função XPath para distinguir elementos XML por nomes em vez de suas posições.SQL #1
Saída
SQL #2
Saída