É possível executar várias atualizações com uma única instrução SQL UPDATE?

Digamos que eu tenha uma tabela tbl com colunas id e title . Eu preciso mudar todos os valores da coluna de título:

  1. de ‘a-1’ a ‘a1’
  2. de ‘a.1’ a ‘a1’
  3. de ‘b-1’ a ‘b1’,
  4. de ‘b.1’ para ‘b1’.

Agora, estou executando duas instruções UPDATE:

UPDATE tbl SET title='a1' WHERE title IN ('a-1', 'a.1') UPDATE tbl SET title='b1' WHERE title IN ('b-1', 'b.1') 

Isso não é de todo um problema, se a tabela for pequena, e a instrução única for concluída em menos de um segundo e você precisar apenas de algumas instruções para executar.

Você provavelmente o convidou – eu tenho uma mesa enorme para lidar (uma declaração completa em cerca de 90 segundos), e eu tenho um grande número de atualizações para executar.

Então, é possível mesclar as atualizações para que apenas digitalizasse a tabela uma vez? Ou talvez haja uma maneira melhor de lidar em uma situação como essa.

EDIT: Note que os dados reais com os quais estou trabalhando e as alterações nos dados que tenho que executar não são tão simples assim – as strings são mais longas e não seguem nenhum padrão (são os dados do usuário, portanto, nenhuma suposição pode ser feito – pode ser qualquer coisa).

Em um caso mais geral, onde poderia haver muitas centenas de mapeamentos para cada um dos novos valores, você criaria uma tabela separada dos valores antigo e novo e usaria isso na instrução UPDATE. Em um dialeto de SQL:

 CREATE TEMP TABLE mapper (old_val CHAR(5) NOT NULL, new_val CHAR(5) NOT NULL); ...multiple inserts into mapper... INSERT INTO mapper(old_val, new_val) VALUES('a.1', 'a1'); INSERT INTO mapper(old_val, new_val) VALUES('a-1', 'a1'); INSERT INTO mapper(old_val, new_val) VALUES('b.1', 'b1'); INSERT INTO mapper(old_val, new_val) VALUES('b-1', 'b1'); ...etcetera... UPDATE tbl SET title = (SELECT new_val FROM mapper WHERE old_val = tbl.title) WHERE title IN (SELECT old_val FROM mapper); 

Ambas as declarações selecionadas são cruciais. A primeira é uma subconsulta correlacionada (não necessariamente rápida, mas mais rápida do que a maioria das alternativas, se a tabela do mapeador tiver milhares de linhas) que extrai o novo valor da tabela de mapeamento que corresponde ao valor antigo. O segundo garante que apenas as linhas que possuem um valor na tabela de mapeamento sejam modificadas; isso é crucial, caso contrário, o título será definido como null para as linhas sem uma input de mapeamento (e esses eram os registros que estavam OK antes de você começar).

Para algumas alternativas, as operações do CASE são OK. Mas se você tiver centenas, milhares ou milhões de mapeamentos para executar, provavelmente excederá os limites do tamanho da instrução SQL no seu DBMS.

Você pode usar uma declaração e um número de declarações de caso

 update tbl set title = case when title in ('a-1', 'a.1') then 'a1' when title in ('b-1', 'b.1') then 'b1' else title end 

Naturalmente, isso causará uma gravação em todos os registros e, com índices, pode ser um problema, portanto, você pode filtrar apenas as linhas que deseja alterar:

 update tbl set title = case when title in ('a-1', 'a.1') then 'a1' when title in ('b-1', 'b.1') then 'b1' else title end where title in ('a.1', 'b.1', 'a-1', 'b-1') 

Isso reduzirá o número de gravações na tabela.

Trabalhando fora da resposta de Jonathan.

 UPDATE tbl SET title = new_val FROM mapper WHERE title IN (SELECT old_val FROM mapper) AND mapper.old_val = tbl.title; 

Sua versão inicial exigiria um grande número de leituras para a tabela do mapeador.

Se as transformações forem tão simples quanto os seus exemplos, você poderá fazer a atualização com um pouco de manipulação de string:

 UPDATE tbl SET title = left(title, 1) + right(title, 1) WHERE title IN ('a-1', 'a.1', 'b-1', 'b.1') 

Algo assim funcionaria para você?

Ou

  Update Table set title = Replace(Replace(title, '.', ''), '-', '') Where title Like '[ab][.-]1'