简体   繁体   English

Oracle:拆分分隔字符串并选择大于输入日期的日期

[英]Oracle: Split delimited string and pick date greater than the input date

I have a comma demilited string as a value in a column like below.我有一个逗号分隔的字符串作为如下列中的值。

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

Within that, each string has three columns combined and delimited by space.其中,每个字符串由三列组合而成,并由空格分隔。

So the requirement here is to pick the date greater and closer to the given input date and get the 2nd column.所以这里的要求是选择更大更接近给定输入日期的日期并获取第二列。

Example: If the input date is 01-AUG-2015 then my output should be 78 since its the closer one.示例:如果输入日期是01-AUG-2015,那么我的输出应该是78,因为它是更接近的日期。 If no dates greater than the input date then output should be empty.如果没有日期大于输入日期,则输出应为空。

This is a complex requirement, which, as commented by Gordon Linoff, would be much simpler to solve if data was properly spread already.这是一个复杂的要求,正如 Gordon Linoff 所评论的那样,如果数据已经正确传播,那么解决起来就会简单得多。

Here is an approach :这是一种方法:

  • First use a recursive CTE with REGEXP_SUBSTR and CONNECT BY to split the string into rows, using the comma separataor首先使用带有REGEXP_SUBSTRCONNECT BY的递归 CTE 将字符串拆分为行,使用逗号分隔符
  • Then split each row into 3 columns, again with REGEXP_SUBSTR and the space separator然后将每一行分成 3 列,再次使用REGEXP_SUBSTR和空格分隔符
  • Then use oracle window functions DENSE_RANK and KEEP to isolate the relevant row然后使用oracle窗口函数DENSE_RANKKEEP来隔离相关行

Assuming that data comes from column str in table my_table :假设数据来自表my_table str列:

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

... where ? ……在哪儿? is the input date.是输入日期。

* db<>fiddle here * db<>在这里拨弄

 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  

Here's one option, based on sample data you provided.这是基于您提供的示例数据的一种选择。

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>

What does it do?它有什么作用?

  • TEST is your sample table (represented by a CTE) TEST是您的示例(由 CTE 表示)
  • T_COMMA splits comma-separated values string into rows (so you get 5 rows out of sample data) T_COMMA将逗号分隔的值字符串拆分为行(因此您从样本数据中获得 5 行)
  • T_DIFF extract each part of the sub-string (ie each row), calculates the difference between sample date and parametrized date, ranks them by absolute value of the difference - RN = 1 is the "closest" date T_DIFF提取子串的每一部分(即每一行),计算样本日期和参数化日期之间的差异,按差异的绝对值对它们进行排名 - RN = 1是“最接近”的日期
  • the final SELECT just returns that "closest" value最后的SELECT只返回那个“最接近”的值

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM