Eu vi uma instrução TSQL concisa que efetivamente divide uma string em seus caracteres constituintes, um por linha, com o objetivo de avaliar o ascii
valor de cada caractere.
Se estou lendo a consulta corretamente, efetivamente, 3 CTEs estão sendo usados para preparar uma tabela de 1 coluna contendo 10.000 linhas, cada uma com o valor '0'.
Um quarto CTE é definido da seguinte forma:
cteTally(n) AS(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) n
FROM E4
)
Posteriormente, este CTE é associado a uma tabela contendo uma coluna com as strings de interesse, com o seguinte select
:
SELECT n, SUBSTRING(LastName, n, 1), ASCII( SUBSTRING(LastName, n, 1))
Ou seja, o número da linha n, o enésimo caractere em LastName e o valor ascii desse caractere.
Minhas dúvidas se referem à over
cláusula do CTE acima.
Essencialmente, o que exatamente ele está fazendo?
Se estamos consultando row_number de 10.000 linhas idênticas, por que precisamos de uma order by
cláusula? Por que o put é order by
colocado em uma over
cláusula e não como uma order by
cláusula para a select
instrução - especialmente porque a over
cláusula nem especifica nenhuma partição? (Presumo que isso significa que a janela sobre a qual row_number
opera são as 10.000 linhas completas?) E o que significa ordenar select null
?
ROW_NUMBER() é uma função de janela de classificação, e as funções de janela de classificação requerem uma cláusula ORDER BY obrigatória. Se você tentar escrevê-lo sem o ORDER BY, receberá um erro de sintaxe.
O truque com a subconsulta foi descoberto por alguém que blogou sobre isso, como uma otimização de desempenho. O SQL Server sempre executa uma operação de classificação, pois as constantes não são permitidas para a cláusula ORDER BY:
E nem são inteiros que são tratados como índices:
Acontece que devido a alguma falha no código, você pode contornar essa limitação usando uma subconsulta, que por algum motivo é permitida, e elimina o operador de classificação.
Você pode usar qualquer constante na subconsulta, o NULL é provavelmente uma reminiscência do hábito de usar SELECT NULL dentro de predicados EXISTS, que no início da história do SQL Server teve um impacto no desempenho em oposição a * ou qualquer outra expressão de coluna, como o otimizador não foi inteligente o suficiente para ignorá-lo.
HTH
UPDATE @Erik-Darling comentou que você também pode contornar isso usando expressões computadas:
A cláusula OVER define a ordenação (e particionamento se PARTITION BY estiver incluído) do conjunto de linhas antes de aplicar a função de janela selecionada. Como você pode usar várias funções do Windows em uma única consulta, cada uma requer seu próprio particionamento e ordenação para garantir que os dados sejam retornados conforme desejado.
No seu exemplo, ROW_NUMBER() está sendo usado para gerar um número de linha sequencial para cada linha no CTE. SELECT NULL é usado porque não há nenhuma ordem específica necessária, mas uma cláusula ORDER BY é necessária para uma função de janela.
Outra maneira de conseguir a mesma coisa seria usar uma coluna IDENTITY, no entanto, que tem outras implicações e requer alterações em uma tabela existente ou a criação de uma tabela temporária. A função de janela ROW_NUMBER em um CTE permite que essa identidade seja gerada em tempo real.
Para responder à sua pergunta específica:
Ele está ordenando as linhas em E4 'aleatoriamente' antes de aplicar a função de janela ROW_NUMBER() a esse conjunto de resultados para produzir uma lista de números de linha igual ao número de linhas em E4. OVER pode ser traduzido como "Busque-me um conjunto de resultados com esta ordenação e particionamento e aplique (OVER) esta função de janela a esse conjunto de resultados independente da ordenação na instrução SELECT principal".
Mais informações: Cláusula OVER