Estou tentando gerar e duplicar vários UNIQUEIDENTIFIER
valores usando NEWID()
como dados de teste. A seguir, minha tentativa é primeiro gerar valores N1 e, em seguida, usar a CROSS APPLY
para duplicar esses valores N2 vezes cada:
SELECT *
FROM (
SELECT
S1.value,
NEWID() AS Id
FROM GENERATE_SERIES(1, 3) S1
) S1
CROSS APPLY (
SELECT
S2.value,
S1.Id -- Trying to repeat the same ID value multiple times
FROM GENERATE_SERIES(1, 2) S2
) S2
ORDER BY S1.Value, S2.Value
Resultados desejados:
valor | Eu ia | valor | Eu ia |
---|---|---|---|
1 | 26d1f8c0-05e8-4d6f-91ab-f97ce13f79fb | 1 | 26d1f8c0-05e8-4d6f-91ab-f97ce13f79fb |
1 | 26d1f8c0-05e8-4d6f-91ab-f97ce13f79fb | 2 | 26d1f8c0-05e8-4d6f-91ab-f97ce13f79fb |
1 | 26d1f8c0-05e8-4d6f-91ab-f97ce13f79fb | 3 | 26d1f8c0-05e8-4d6f-91ab-f97ce13f79fb |
2 | 4743c229-0c3c-44fd-b9f8-9406b06e350e | 1 | 4743c229-0c3c-44fd-b9f8-9406b06e350e |
2 | 4743c229-0c3c-44fd-b9f8-9406b06e350e | 2 | 4743c229-0c3c-44fd-b9f8-9406b06e350e |
2 | 4743c229-0c3c-44fd-b9f8-9406b06e350e | 3 | 4743c229-0c3c-44fd-b9f8-9406b06e350e |
Resultados reais:
valor | Eu ia | valor | Eu ia |
---|---|---|---|
1 | 26d1f8c0-05e8-4d6f-91ab-f97ce13f79fb | 1 | 26d1f8c0-05e8-4d6f-91ab-f97ce13f79fb |
1 | 8dbf1b38-f6af-4b7e-9b3d-65f3df4bb017 | 2 | 8dbf1b38-f6af-4b7e-9b3d-65f3df4bb017 |
1 | 2eddb5e1-4f3e-4938-ab7b-49740a20a779 | 3 | 2eddb5e1-4f3e-4938-ab7b-49740a20a779 |
2 | 4743c229-0c3c-44fd-b9f8-9406b06e350e | 1 | 4743c229-0c3c-44fd-b9f8-9406b06e350e |
2 | f8a66f07-04da-44ab-af7b-47a747dc6bf6 | 2 | f8a66f07-04da-44ab-af7b-47a747dc6bf6 |
2 | 034876b6-8cf5-4264-810d-de5202554d77 | 3 | 034876b6-8cf5-4264-810d-de5202554d77 |
Entendo que NEWID()
isso gerará valores exclusivos para cada linha onde for usado, mas teria pensado que, quando usados em uma subconsulta, os valores seriam gerados nessa subconsulta em vez de serem gerados no nível mais externo. Não consigo encontrar uma explicação clara desse comportamento na documentação do NEWID ou em outro lugar.
Tentei inserir cálculos intermediários usando CAST()
, TOUPPER()
e REPLACE()
, que achei que poderiam capturar e solidificar os NEWID()
valores. Também tento encerrar a primeira parte em um CTE. Ainda não consigo repetir os valores gerados.
Posso fazer isso em várias etapas usando uma tabela #temp ou uma variável @table, mas queria saber se existe uma maneira de fazer isso em uma única instrução.
Aqui está outro caso semelhante:
-- Another similar case
WITH CTE AS (
SELECT NEWID() AS Id -- Is this one value or many?
)
SELECT *
FROM ( VALUES (1), (2), (3) ) ID(Id)
CROSS JOIN CTE
Seguir:
Eu descobri uma pergunta semelhante no dba stackexchange que me apontou para um relatório e discussão de bug do Microsoft Connect de 15 anos , que terminou com o relatório de bug sendo fechado como não será corrigido, funções conforme projetado. A justificativa é que "o otimizador não garante o tempo ou o número de execuções de funções escalares" e "é muito difícil definir com precisão ... o que significa o comportamento uma vez por linha ".
Essa mesma postagem teve um comentário tardio que encontrou uma solução alternativa usando uma combinação de GROUP BY
e FULL OUTER JOIN
para persuadir o comportamento desejado, mas comentários posteriores sugerem que esse ainda era um comportamento indefinido.
Também encontrei alguma documentação on-line de livros antigos de 2005 que inclui uma prática recomendada: "Limitar o uso de funções não determinísticas às listas de seleção mais externas". Não consegui encontrar o mesmo na documentação atual, mas talvez não estivesse procurando no lugar certo.
Portanto, embora a resposta de ValNik abaixo sugira uma solução alternativa envolvendo GROUP BY
, acho que isso também é construído em terreno instável. (A resposta de ValNik, na verdade, começa com um comentário “não faz sentido”.)
Também descobri que adicionar uma IS NOT NULL
verificação também estimula o resultado desejado ( violino ). Novamente, este é provavelmente um comportamento indefinido que parece funcionar - é melhor evitar.
Resumindo, provavelmente é melhor seguir a antiga prática "Limitar o uso de funções não determinísticas às listas de seleção mais externas", o que significa selecionar uma tabela temporária ou variável de tabela, conforme recomendado por Thom A e documentado como resposta.