SQL查询将与多个范围匹配的数字列表转换为值列表

Posted

技术标签:

【中文标题】SQL查询将与多个范围匹配的数字列表转换为值列表【英文标题】:SQL query to translate a list of numbers matched against several ranges, to a list of values 【发布时间】:2010-04-14 08:35:21 【问题描述】:

我需要将某个范围内的数字列表转换为按优先级列排序的值列表。该表具有以下值:

| YEAR | R_MIN |  R_MAX | VAL | PRIO |
------------------------------------
  2010   18000    90100   52    6
  2010  240000   240099   82    3
  2010  250000   259999   50    5
  2010  260000   260010   92    1
  2010  330000   330010   73    4
  2010  330011   370020   50    5
  2010  380000   380050   84    2

不同年份的范围会有所不同。一年内的范围永远不会重叠。

输入将是年份和可能在这些范围内的数字列表。输入数字的列表将很小,1 到 10 个数字。输入数字示例:

(20000, 240004, 375000, 255000)

通过该输入,我想获得一个按优先级列排序的列表,或单个值:

82
50
52

我在这里感兴趣的唯一值是 82,所以 UNIQUE 和 MAX_RESULTS=1 就可以了。可以很容易地对每个数字进行一次查询,然后在 Java 代码中对其进行排序,但我更愿意在单个 SQL 查询中进行。

在 Oracle 数据库中运行什么 SQL 查询会给我想要的结果?

(注意,这不是关于splitting an input string,而是关于将值列表中的每个值与不同列中定义的范围进行匹配。)

【问题讨论】:

Is there a function to split a string in PL/SQL?的可能重复 【参考方案1】:

我猜你想将这组数字作为字符串传递并拆分为单独的数字。这比您想象的要难,因为 Oracle 没有内置标记器。很奇怪吧?

有许多 PL/SQL 标记器解决方案围绕着 Das Interwabs。我正在使用Anup Pani's implementation 的变体,它使用正则表达式(因此只有Oracle 10g 或更高版本)。我的变体返回一个我已声明为 SQL 类型的数字数组:

SQL> create or replace type numbers as table of number
  2  /

Type created.

SQL>

这意味着我可以在 SELECT 语句中将它用作 TABLE() 函数的输入:

SQL> select * from table (str_to_number_tokens('20000, 240004, 375000, 255000'))
  2  /

COLUMN_VALUE
------------
       20000
      240004
      375000
      255000

SQL>

这意味着我可以将你的数字字符串转换成一个表格,我可以在查询中加入该表格,如下所示:

SQL> select val
  2  from t23
  3       , ( select column_value as i_no
  4           from table (str_to_number_tokens('20000, 240004, 375000, 255000')) ) sq
  5  where t23.year = 2010
  6  and   sq.i_no between t23.r_min and t23.r_max
  7  order by t23.priority
  8  /

       VAL
----------
        82
        50
        52

SQL>

【讨论】:

谢谢!这确实比我最初想象的要复杂得多。 @ClaesMogren - 这是第一次有点傻的事情,因为我们必须建立一些基础设施。但在那之后就很容易了。【参考方案2】:

我认为您的第一个任务是将数字列表转换为您可以加入的结果集(即内存表)。我不了解 Oracle,因此可能有一种简单的方法可以做到这一点,但如果没有,您将需要编写某种用户定义的函数来执行此操作。它不应该太难,性能也不是问题,因为列表很小。然后,您可以连接到该表。像这样的:

SELECT yt.val
FROM your_table yt
JOIN your_parse_numbers_function(@inputlist) il
ON il.value >= yt.R_MIN AND il.value <= yt.R_MAX
WHERE yt.YEAR = @year

如果您愿意,您可以将其限制为 1 个结果,但如果您关于范围不重叠的假设是正确的,那么它应该只返回 1。

【讨论】:

嗯...这会起作用,但我不确定如何制作结果集。我去看看。

以上是关于SQL查询将与多个范围匹配的数字列表转换为值列表的主要内容,如果未能解决你的问题,请参考以下文章

使用Java 8模式匹配将地图转换为列表

列表中每个值的 SQL 查询循环

sql 将逗号分隔的字符串拆分为值列表(返回游标)

无法将与当前打开页面匹配的活动类添加到菜单列表项

SQL查询以获取时间范围列表的平均值

获取与 SQL 查询中的列表匹配的所有行