Problema de alto nível: Quero atualizar uma tabela existente para preencher uma coluna existente com 32 bytes gerados aleatoriamente, codificados em base64. Os dados aleatórios devem ser diferentes para cada linha.
Ignorando por um momento o requisito de codificação base64, a solução é simples, conforme ilustrado neste código de exemplo:
DECLARE @table TABLE (
id int,
bin varbinary(max) null
)
-- put a few rows in the table
insert into @table (id) values (1)
insert into @table (id) values (2)
insert into @table (id) values (3)
-- perform the update
update @table
set bin = CRYPT_GEN_RANDOM(32)
-- check result
select *
from @table
Isso funciona como esperado. CRYPT_GEN_RANDOM(32)
gera um valor diferente para cada linha atualizada. Agora tente adicionar o requisito de codificação base64:
DECLARE @table TABLE (
id int,
txt nvarchar(max) null
)
-- put a few rows in the table
insert into @table (id) values (1)
insert into @table (id) values (2)
insert into @table (id) values (3)
-- perform the update
update @table
set txt = (SELECT CRYPT_GEN_RANDOM(32) FOR XML PATH(''), BINARY BASE64)
-- check result
select *
from @table
Isso não funciona: ele coloca o mesmo valor em cada linha. Eu tentei empacotar a codificação base64 em um UDF, para ver se isso ajudaria:
CREATE FUNCTION ConvertBytesToBase64
(
@bytes varbinary(max)
)
RETURNS nvarchar(max)
AS
BEGIN
DECLARE @result nvarchar(max)
SET @result = (SELECT @bytes FOR XML PATH(''), BINARY BASE64)
RETURN @result
END
GO
E então a declaração de atualização se torna:
update @table
set txt = ConvertBytesToBase64(CRYPT_GEN_RANDOM(32))
Mas isso ainda produz o mesmo valor em todas as linhas.
O que eu fundamentalmente não entendo é, dado que o SQL Server avalia CRYPT_GEN_RANDOM(32)
para cada linha (o que parece sensato), por que ele não avalia ConvertBytesToBase64(CRYPT_GEN_RANDOM(32))
para cada linha? Como posso fazer com que ele avalie para cada linha? (e talvez relacionado, há uma maneira melhor de fazer codificação base64 no SQL Server 2019+?)