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

时间:2010-04-14 08:35:22

标签: sql oracle plsql tokenize

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

| 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,而是将值列表中的每个值与不同列中定义的范围相匹配。)

2 个答案:

答案 0 :(得分:4)

我猜你想把这组数字作为字符串传递并分成单个数字。这比你想象的要难,因为Oracle没有内置的tokenizer。很奇怪,是吗?

有许多PL / SQL标记器解决方案可以解决Das Interwabs问题。我正在使用Anup Pani's implementation的变体,它使用Regex(因此只有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>

答案 1 :(得分:1)

我认为您的第一个任务是将数字列表转换为可以加入的结果集(即内存表)。我不了解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。