Как определить есть ли NULL в некоем интервале
Дана таблица с тремя полями
| group_id | index_old | index_new |
|---|---|---|
| 1 | 2 | 2 |
| 1 | 4 | 4 |
| 1 | 7 | null |
| 1 | 8 | 8 |
| 1 | 12 | 12 |
| 2 | 14 | null |
| 2 | 18 | null |
| 2 | 19 | 19 |
| 2 | 23 | 23 |
| 2 | 24 | 24 |
| 2 | 29 | 29 |
| 3 | 30 | null |
| 3 | 31 | null |
| 3 | 34 | 34 |
| 3 | 37 | 37 |
| 3 | 39 | null |
| 3 | 40 | 40 |
| 3 | 42 | null |
| 3 | 47 | 47 |
Столбец index_new повторяет столбец index_old, но некоторые значения пропущены. Столбец index_old уникален и возрастает. Разница между соседними значениями случайна. group_id уникален и возрастает, количество значений в каждой группе случайно.
Надо получить сгруппированную по group_id таблицу, в которой будет указано (все равно как - лучше булевым значением, но можно и какой-то цифрой) отсутствует ли NULL после минимального не NULL значения в каждой группе в столбце index_new. Другими словами - если в начале группы идут NULL - это нас не беспокоит, дальше появляется не-NULL-значение и нам надо убедится, что после этого значения нету пропущенных.
В примере: В первой группе минимум 2, после него идет NULL вместо 7 - группа ошибочная. Во второй группе сначала идут NULL, минимум 19, после этого NULL не присутствует - подходит. В третьей группе сначала NULL, минимум 34, затем NULL вместо 39 и 42 - ошибка.
Итого в ответе:
| group_id | null_flag |
|---|---|
| 1 | f |
| 2 | t |
| 3 | f |
Или, в ответе можно так, посчитать количество NULL:
| group_id | null_count |
|---|---|
| 1 | 1 |
| 2 | 0 |
| 3 | 2 |
Потом я отфильтрую по нулю.
Что я делаю: группирую, беру минимум в каждой группе в index_new, считаю количество объектов бОльших минимума для обоих столбцов и сравниваю количество. Если разница равна нулю - это успех, не равна нулю - неудача.
Можно по-другому, например с помощью EXCEPT или INTERSECT. (Кстати, какой способ лучше - считать и сравнивать количество или пересечь и посчитать, что там осталось?)
Но вопрос вот в чем: во всех моих решениях надо применять сравнение с эталонным столбцом, то есть я не нашел способа, чтобы используя только столбец index_new определить есть ли в нем NULL-значения после определенного значения. Можно ли так сделать? Второй вопрос: какие решения вам видятся более удачными чем мои?
UPD
Пока перечитывал вопрос (кстати, о пользе задавать вопросы), подумал, что можно не сравнивать с количеством в другом столбце, а считать и сравнивать с count(*). Но не уверен, что это будет быстрее.
Ответы (1 шт):
Можно выбрать строки, когда index_new после not null идет null. Пример:
select *
from(
select *
,lag(index_new,1,index_new)over(partition by group_id order by index_old) prev_new
from test
) t
where index_new is null and prev_new is not null
| group_id | index_old | index_new | prev_new |
|---|---|---|---|
| 1 | 7 | null | 4 |
| 3 | 39 | null | 37 |
| 3 | 42 | null | 40 |
Группировка обычная. Если счетчик равен 0, значит группа не включает искомые строки.
select group_id,
sum(case when index_new is null and prev_new is not null then 1 else 0 end) cnt
from(
select *
,lag(index_new,1,index_new)over(partition by group_id order by index_old) prev_new
from test
) t
group by group_id
| group_id | cnt |
|---|---|
| 1 | 1 |
| 2 | 0 |
| 3 | 2 |
Из двух подряд идущих null будет взят только 1, если это имеет значение.