Это сложное требование, которое, как прокомментировал Гордон Линофф, было бы гораздо проще решить, если бы данные были уже правильно распределены.
Вот подход:
- Сначала используйте рекурсивный CTE с
REGEXP_SUBSTR
и CONNECT BY
, чтобы разбить строку на строки, используя запятую
- Затем разделите каждую строку на 3 столбца, снова с помощью
REGEXP_SUBSTR
и разделителя пробелов
- Затем используйте функции окна оракула
DENSE_RANK
и KEEP
, чтобы выделить соответствующую строку
Предполагая, что данные поступают из столбца str
в таблице my_table
:
WITH
cte0 AS (
SELECT TRIM(REGEXP_SUBSTR(str, '[^,]+', 1, LEVEL)) str
FROM my_table
CONNECT BY INSTR(str, ',', 1, LEVEL - 1) > 0
),
cte1 AS (
SELECT
TO_DATE(REGEXP_SUBSTR(str, '\S+', 1, 1), 'yyyy-mm-dd') dt,
REGEXP_SUBSTR(str, '\S+', 1, 2) val1,
REGEXP_SUBSTR(str, '\S+', 1, 3) val2
FROM cte0
ORDER BY 1 DESC
)
SELECT
MIN(dt) keep (dense_rank first order by dt) as dt,
MIN(val1) keep (dense_rank first order by dt) as val1,
MIN(val2) keep (dense_rank first order by dt) as val2
FROM cte1
WHERE dt > TO_DATE(?, 'yyyy-mm-dd')
... где ?
- дата ввода.
* дБ <> скрипка здесь
with
data as (
SELECT
'2015/04/01 11 GG, 2015/08/03 78 KK, 2012/12/12 44 TT, 2015/09/01 77 YY, 2015/09/01 88 ZZ' str
FROM DUAL
),
cte0 AS (
SELECT TRIM(REGEXP_SUBSTR(str, '[^,]+', 1, LEVEL)) str
FROM data
CONNECT BY INSTR(str, ',', 1, LEVEL - 1) > 0
),
cte1 AS (
SELECT
TO_DATE(REGEXP_SUBSTR(str, '\S+', 1, 1), 'yyyy-mm-dd') dt,
REGEXP_SUBSTR(str, '\S+', 1, 2) val1,
REGEXP_SUBSTR(str, '\S+', 1, 3) val2
FROM cte0
ORDER BY 1 DESC
)
SELECT
min(dt) keep (dense_rank first order by dt) as dt,
min(val1) keep (dense_rank first order by dt) as val1,
min(val2) keep (dense_rank first order by dt) as val2
FROM cte1
WHERE dt > TO_DATE('2015-08-01', 'yyyy-mm-dd')
-------------------------
DT | VAL1 | VAL2
:-------- | :--- | :---
03-AUG-15 | 78 | KK