[英]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 :这是一种方法:
REGEXP_SUBSTR
and CONNECT BY
to split the string into rows, using the comma separataorREGEXP_SUBSTR
和CONNECT BY
的递归 CTE 将字符串拆分为行,使用逗号分隔符REGEXP_SUBSTR
and the space separatorREGEXP_SUBSTR
和空格分隔符DENSE_RANK
and KEEP
to isolate the relevant rowDENSE_RANK
和KEEP
来隔离相关行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.是输入日期。
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
是“最接近”的日期SELECT
just returns that "closest" valueSELECT
只返回那个“最接近”的值
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.