Сохранить значение последовательности

Пытаюсь решить задачу, которую представлю здесь в упрощенном виде. У нас есть в таблице возрастающая последовательность ключей (ключи могут повторяться, могут быть и "дырки") и некоторые значения к каждому ключу. Наша задача - выбрать SELECT'ом только по одной строке с каждым ключом так, чтобы было как можно меньше смен значения с возростанием ключа. Чтобы упростить задачу решил просто пытаться взять для каждого ключа то же значение, что и у предыдущего. Пример:

| key | Value  |
---------------
| 1 | A |
| 1 | B |
| 2 | B |
| 3 | B |
| 4 | A |
| 4 | B |
| 5 | D |
| 5 | E |
| 6 | A |

Хотим получить:

| key | Value  |
---------------
| 1 | B |
| 2 | B |
| 3 | B |
| 4 | B |
| 5 | D |
| 6 | A |

То есть строка "4 | A" была пропущена, т.к. с ключом 3 у нас стоит B, поэтому и с ключом 4 выбрали B. С ключом 1 выбрали B по случайности (т.к. предыдущего значения нет). Аналогично с ключами 5 и 6 выбраны случайные строки, т.к. среди их значений (D и E для 5 и A для 6) нет предыдущего значения (4|B).

p.s. желательно обойтись без рекурсивного запроса


Ответы (1 шт):

Автор решения: Виталий Яндулов

Это наверняка не лучшее решение, но в какой-то степени оно все-таки работает:

WITH A AS (
    SELECT 1 AS KEY, 'A' AS VALUE FROM DUAL UNION ALL
    SELECT 1 AS KEY, 'B' AS VALUE FROM DUAL UNION ALL
    SELECT 2 AS KEY, 'B' AS VALUE FROM DUAL UNION ALL
    SELECT 3 AS KEY, 'B' AS VALUE FROM DUAL UNION ALL
    SELECT 4 AS KEY, 'A' AS VALUE FROM DUAL UNION ALL
    SELECT 4 AS KEY, 'B' AS VALUE FROM DUAL UNION ALL
    SELECT 5 AS KEY, 'D' AS VALUE FROM DUAL UNION ALL
    SELECT 5 AS KEY, 'E' AS VALUE FROM DUAL UNION ALL
    SELECT 6 AS KEY, 'A' AS VALUE FROM DUAL
)
SELECT key, value
  FROM (SELECT ROW_NUMBER() OVER(PARTITION BY key ORDER BY row_diff, value_cnt DESC) AS rn,
               key,
               value
          FROM (SELECT SUM(1) OVER(PARTITION BY VALUE ORDER BY KEY ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) value_cnt,
                       KEY - LAG(KEY, 1, -10000000 + KEY) OVER(PARTITION BY VALUE ORDER BY KEY) row_diff,
                       key, value
                  FROM A))
 WHERE rn = 1;

В нашем примере выдаст ответ (как помним, первая строка рандомна):

| key | Value  |
---------------
| 1 | A |
| 2 | B |
| 3 | B |
| 4 | B |
| 5 | D |
| 6 | A |

Что в целом вполне можно использовать

→ Ссылка