Eu tenho a seguinte entrada:
id | value
----+-------
1 | 136
2 | NULL
3 | 650
4 | NULL
5 | NULL
6 | NULL
7 | 954
8 | NULL
9 | 104
10 | NULL
Espero o seguinte resultado:
id | value
----+-------
1 | 136
2 | 136
3 | 650
4 | 650
5 | 650
6 | 650
7 | 954
8 | 954
9 | 104
10 | 104
A solução trivial seria juntar as tabelas com uma <
relação e, em seguida, selecionar o MAX
valor em GROUP BY
:
WITH tmp AS (
SELECT t2.id, MAX(t1.id) AS lastKnownId
FROM t t1, t t2
WHERE
t1.value IS NOT NULL
AND
t2.id >= t1.id
GROUP BY t2.id
)
SELECT
tmp.id, t.value
FROM t, tmp
WHERE t.id = tmp.lastKnownId;
No entanto, a execução trivial desse código criaria internamente o quadrado da contagem das linhas da tabela de entrada ( O (n ^ 2) ). Eu esperava que o t-sql o otimizasse - em nível de bloco / registro, a tarefa a ser executada é muito fácil e linear, essencialmente um loop for ( O (n) ).
No entanto, em meus experimentos, o MS SQL 2016 mais recente não pode otimizar essa consulta corretamente, tornando impossível a execução dessa consulta para uma tabela de entrada grande.
Além disso, a consulta precisa ser executada rapidamente, inviabilizando uma solução igualmente fácil (mas muito diferente) baseada em cursor.
Usar alguma tabela temporária com suporte de memória pode ser um bom comprometimento, mas não tenho certeza se ela pode ser executada significativamente mais rapidamente, considerando que meu exemplo de consulta usando subconsultas não funcionou.
Também estou pensando em desenterrar algumas funções de janelas dos documentos do t-sql, o que pode ser complicado para fazer o que eu quero. Por exemplo, a soma cumulativa está fazendo algo muito semelhante, mas não consegui enganá-lo para fornecer o último elemento não nulo, e não a soma dos elementos anteriores.
A solução ideal seria uma consulta rápida sem código processual ou tabelas temporárias. Como alternativa, também uma solução com tabelas temporárias é boa, mas a iteração da tabela proceduralmente não é.
fonte