У мене є наступний вклад:
id | value
----+-------
1 | 136
2 | NULL
3 | 650
4 | NULL
5 | NULL
6 | NULL
7 | 954
8 | NULL
9 | 104
10 | NULL
Я очікую наступного результату:
id | value
----+-------
1 | 136
2 | 136
3 | 650
4 | 650
5 | 650
6 | 650
7 | 954
8 | 954
9 | 104
10 | 104
Тривіальним рішенням буде з'єднання таблиць із <
відношенням, а потім вибір MAX
значення у 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;
Однак тривіальне виконання цього коду створило би внутрішньо квадрат лічильників рядків вхідної таблиці ( O (n ^ 2) ). Я очікував, що t-sql її оптимізує - на рівні блоку / запису завдання зробити дуже просто та лінійно, по суті для циклу ( O (n) ).
Однак, на моїх експериментах, останній MS SQL 2016 не може правильно оптимізувати цей запит, що робить цей запит неможливим для виконання великої таблиці введення.
Крім того, запит повинен запускатися швидко, роблячи аналогічно легким (але дуже різним) рішення на основі курсору нездійсненним.
Використання деякої підтримуваної пам’яттю тимчасової таблиці може бути хорошим компромісом, але я не впевнений, чи можна її запустити значно швидше, вважаючи, що мій приклад запиту за допомогою підзапитів не спрацював.
Я також замислююся над тим, щоб викопати якусь функцію вікон у документах t-sql, що можна підманути робити те, що я хочу. Наприклад, сукупна сума робить дуже схожу, але я не міг її обдурити, щоб дати останній ненульовий елемент, а не суму елементів раніше.
Ідеальним рішенням буде швидкий запит без процедурного коду або тимчасових таблиць. Як варіант, також рішення з тимчасовими таблицями нормально, але процедуру повторення таблиці - це не так.