基于输入范围的排序逗号分隔字符串的 MAX/MIN 的 SQL 查询
Posted
技术标签:
【中文标题】基于输入范围的排序逗号分隔字符串的 MAX/MIN 的 SQL 查询【英文标题】:SQL query for MAX/MIN of a sorted comma separated string based on an input range 【发布时间】:2020-12-20 12:33:25 【问题描述】:我在 oracle 表中有一个列,其中包含按如下排序顺序以逗号分隔的日期值。
ID|LIST_OF_DATES
--|---------------
1 |2020-11-01,2020-11-04,2020-11-05,2020-11-10,2020-11-12,2020-11-14,2020-11-16,.....2020-11-26,2020-11-30
这里的日期列表不是连续的日期列表。我的要求是获取落在输入窗口内的日期列表的最大值的索引。上面提供的数据的示例输出。
INPUT_DATE_FROM: 2020-11-10
INPUT_DATE_TO: 2020-11-15
对于上述输入范围.. 我们有三个日期在该范围内,它们是 2020-11-10,2020-11-12,2020-11-14,其中 2020-11-14 是最大值。 2020-11-14 是日期列表中的第 6 个值,这是我需要的查询的输出。
OUTPUT:
ID|INDEX_OF_MAX_DATE
1 |5 (Assuming 0 is the start index)
当输入窗口更改为 2020-11-25 到 2020-11-30 时,我们只有两个日期,其中 2020-11-30 是最大值。我需要这个最大值的索引。
使用 oracle SQL 获得此结果的最佳方法是什么?我的表将有大约 4 -500 万个唯一 ID,应该对其进行计算。
【问题讨论】:
【参考方案1】:您需要拆分列表,然后选择最大值。这是一种方法:
with dates as (
select regexp_substr(t.list_of_dates, '[^,]+', 1, level) as dte
from t
connect by regexp_substr(t.list_of_dates, '[^,]+', 1, level) is not null
)
select id, max(date)
from dates
where dte >= :start_date_str and date <= :end_date_str
group by id;
也就是说,您应该修复您的数据模型。在一个字符串中存储多个值是不好的。将日期存储为字符串是不好的。
上面假设参数是字符串,就像字符串中的值一样。如果它们是日期,那么您需要将字符串转换为日期。
【讨论】:
缺少日期转换,当前使用保留字作为派生列名。【参考方案2】:您可以使用简单的字符串函数拆分字符串,然后使用解析函数查找列表中最大值的索引:
WITH bounds ( id, list_of_dates, idx, start_pos, end_pos ) AS (
SELECT id,
list_of_dates,
0,
1,
INSTR( list_of_dates, ',', 1 )
FROM table_name
UNION ALL
SELECT id,
list_of_dates,
idx + 1,
end_pos + 1,
INSTR( list_of_dates, ',', end_pos + 1 )
FROM bounds
WHERE end_pos > 0
),
dates ( id, idx, value ) AS (
SELECT id,
idx,
TO_DATE(
CASE end_pos
WHEN 0
THEN SUBSTR( list_of_dates, start_pos )
ELSE SUBSTR( list_of_dates, start_pos, end_pos - start_pos )
END,
'YYYY-MM-DD'
)
FROM bounds
)
SELECT id,
idx,
value
FROM (
SELECT id,
idx,
value,
RANK() OVER ( PARTITION BY id ORDER BY value DESC ) AS rnk
FROM dates
WHERE value BETWEEN DATE '2020-11-10' AND DATE '2020-11-15'
)
WHERE rnk = 1;
其中,对于样本数据:
CREATE TABLE table_name ( ID, LIST_OF_DATES ) AS
SELECT 1, '2020-11-01,2020-11-04,2020-11-05,2020-11-10,2020-11-12,2020-11-14,2020-11-16,2020-11-26,2020-11-30' FROM DUAL
输出:
身份证 | IDX |价值 -: | --: | :----------------- 1 | 5 | 2020-11-14 00:00:00
db小提琴here
或者通过使用:
SELECT t.id,
d.*
FROM table_name t
CROSS APPLY (
SELECT *
FROM (
SELECT LEVEL - 1 AS idx,
TO_DATE(
REGEXP_SUBSTR( t.list_of_dates, '[^,]+', 1, LEVEL ),
'YYYY-MM-DD'
) AS value
FROM DUAL
CONNECT BY
LEVEL <= REGEXP_COUNT( t.list_of_dates, '[^,]+' )
)
WHERE value BETWEEN DATE '2020-11-10' AND DATE '2020-11-15'
ORDER BY
value DESC
FETCH FIRST ROW WITH TIES
) d
db小提琴here
【讨论】:
以上是关于基于输入范围的排序逗号分隔字符串的 MAX/MIN 的 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章