Oracle: разделить строку с разделителями и выбрать дату, превышающую дату ввода - PullRequest
0 голосов
/ 19 января 2019

У меня есть строка, разделенная запятой, в качестве значения в столбце, как показано ниже.

'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'

В этой строке каждая строка состоит из трех столбцов, объединенных и разделенных пробелом.

Таким образом, здесь необходимо выбрать дату больше и ближе к заданной дате ввода и получите 2-й столбец.

Пример: Если дата ввода 01-AUG-2015 , тогда мой вывод должен быть 78 , так как он ближе. Если даты не превышают введенную дату, выходные данные должны быть пустыми.

Ответы [ 2 ]

0 голосов
/ 19 января 2019

Это сложное требование, которое, как прокомментировал Гордон Линофф, было бы гораздо проще решить, если бы данные были уже правильно распределены.

Вот подход:

  • Сначала используйте рекурсивный 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  
0 голосов
/ 19 января 2019

Вот один из вариантов, основанный на предоставленных вами образцах данных.

SQL> with test (col) as
  2    (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' from dual),
  3  t_comma as
  4    (select trim(regexp_substr(col, '[^,]+', 1, level)) col2
  5     from test
  6     connect by level <= regexp_count(col, ',') + 1
  7    ),
  8  t_diff as
  9    (select col2,
 10         substr(col2, 1, 10) c_date,
 11         regexp_substr(col2, '\d+', 1, 4) c_num,
 12         regexp_substr(col2, '\w+$') c_let ,
 13         --
 14         abs(to_date(substr(col2, 1, 10), 'yyyy/mm/dd') -
 15             to_date('&&:par_date', 'yyyy/mm/dd')) diff_days,
 16         --
 17         row_number() over (order by abs(to_date(substr(col2, 1, 10), 'yyyy/mm/dd') -
 18                                         to_date('&&par_date', 'yyyy/mm/dd'))) rn
 19     from t_comma
 20    )
 21  select c_num
 22  from t_diff
 23  where rn = 1;
Enter value for par_date: 2015-08-01

C_NUM
--------------------------------------------------------------------------------
78

SQL>

Что это делает?

  • TEST это ваш образец таблица (представлена ​​CTE)
  • T_COMMA разбивает строку значений, разделенных запятыми, на строки (таким образом, вы получаете 5 строк из выборочных данных)
  • T_DIFF извлекает каждую часть подстроки (т.е. каждую строку), рассчитывает разницу между датой выборки и параметризованной датой, ранжирует их по абсолютному значению разницы - RN = 1 является «ближайшей» датой
  • последний SELECT просто возвращает это "ближайшее" значение
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...