Given a search string (partial number) and a table that has two varchar columns FROM_NUMBER and TO_NUMBER, I want to select rows that contain the search string in any number between FROM_NUMBER and TO_NUMBER (inclusive).
I know LIKE '%xxx%' but this is for matching a column only.
Example: I have the following table NUMBER_RANGE
| ID | PREFIX | FROM_NUMBER | TO_NUMBER |
|----|--------|-------------|------------|
| 1 | +1 | 4081234500 | 4081234599 |
| 2 | +61 | 267222000 | 267222009 |
| 3 | +81 | 11812205 | 11812205 |
| 4 | +61 | 240859600 | 240859600 |
Say, given "4501", it should return row 1 as "4501" is substring of a number "4081234501" which is between "4081234500" and "4081234599"
Given "4081234500" or "4081234509" or "4081234599", it should return row 1.
Given "408", it should return row 1 and 4.
How can I construct a SQL SELECT statement with correct WHERE conditions to return the records I want?
Can I search without expanding FROM_NUMBER to TO_NUMBER on-the-go (because it's possible to have 1000 numbers in a range and it takes too long to process)?
Thanks.
looking to your fist sample .. You could just convert the string as number
select 'OK'
from dual
where 4501 between
CAST(right('4081234500', length('4501')) AS INT)
AND CAST(right('4081234599', length('4501')) AS INT)
;
and for your table assuming my_value contain '4501'
select id
from my_table
where cast(my_value) between
cast(right(FROM_NUMBER, length(my_value)) AS INT)
AND CAST(right(TO_NUMBER, length(my_value)) AS INT)
for the second sample you should use the left part of the string instead of the right and use OR for use the two condition togheter
As far as I understood your problem, I have made query to find if exact number is present as sub string your columns or number that is given present in the last matching numbers of your columns. ie if length of provided number is 2 then last two digits of from and to number will be considered for range search.
You can try following query:
YOUR_NUMBER = 4501
SELECT * FROM TABLE
WHERE FROM_NUMBER LIKE '%' || YOUR_NUMBER || '%'
OR TO_NUMBER LIKE '%' || YOUR_NUMBER || '%'
OR YOUR_NUMBER
BETWEEN MOD(FROM_NUMBER, POWER(10, LENGTH(YOUR_NUMBER)))
AND MOD(TO_NUMBER, POWER(10, LENGTH(YOUR_NUMBER)));
Cheers!!
This query looks complicated but it is not. The idea is to cut numbers into blocks of pattern-length and compare with pattern, just like a man does it:
with
s(str) as (select 81220 from dual),
a as (
select id, str, length(str) ls, from_number fn, to_number tn,
lpad(from_number, length(to_number), '0') s1, to_char(to_number) s2
from number_range join s on length(to_number) >= length(str)),
c(col, id, str, ls, s1, s2, sb1, sb2, match) as (
select 1, id, str, ls, s1, s2, substr(s1, 1, ls), substr(s2, 1, ls),
case when str between substr(s1, 1, ls)
and substr(s2, 1, ls) then 1 end
from a
union all
select col + 1, id, str, ls, s1, s2, substr(s1, col + 1, ls), substr(s2, col + 1, ls),
case when str between substr(s1, col + 1, ls)
and substr(s2, col + 1, ls) then 1 end
from c
where col <= length(s1) - ls and match is null )
select id, str, sb1, sb2, prefix, from_number, to_number
from c join number_range using (id)
where match = 1 order by id, col;
s
- value to find (you can put several values here using union)
a
- data from your table where from_number
is lpadded with zeros to the to_number
's length
c
- is recursive query. I cut first block from both numbers and compare with pattern. If its between the analysis stops ( and match is null
is responsible for that). Otherwise it continues.
Finally I join results (if anything was found) with original data and show which parts of strings where corresponding. This query finds first occurence for each row, if there are more and you want them all remove and match is null
. Hope this helps.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.