regular expression to get all numbers except in a range - sql

I want to get a list ip addresses whose last 3 digits don't fall in the range 0 to 200. I tried using REGEXP_LIKE as below. But it is giving me wrong result.
select * from ip_data
where REGEXP_LIKE(substr(ip_address,instr(ip_address,'.',1,3)+1),'[^0-200]');
It seems to have matched each digits with 0-200 numbers individually.
I want to use only REGEXP_LIKE as I've to take the range from another table where it is stored in the format [0-200].
Any suggestions would be of great help.

Using REGEXP_SUBSTR:
SQL> WITH DATA AS(
2 SELECT '127.0.0.1' ip FROM dual UNION ALL
3 SELECT '127.0.0.201' ip FROM dual
4 )
5 SELECT * FROM DATA
6 WHERE REGEXP_SUBSTR(ip,'[[:digit:]]{1,3}',1, 4)
7 NOT BETWEEN 0 AND 200
8 /
IP
-----------
127.0.0.201
SQL>
Using simple SUBSTR:
SQL> WITH DATA AS(
2 SELECT '127.0.0.1' ip FROM dual UNION ALL
3 SELECT '127.0.0.201' ip FROM dual
4 )
5 SELECT * FROM DATA
6 WHERE to_number(substr(ip,instr(ip,'.',1,3)+1))
7 NOT BETWEEN 0 AND 200
8 /
IP
-----------
127.0.0.201
SQL>
I would go with the simple SUBSTR approach since it is less resource consuming, less CPU utilization, thus better performance.

You don't need regular expression for that:
to_number(substr(ip_address,instr(ip_address,'.',1,3)+1)) not between 0 and 200

Something like this should works:
select ip_address from ip_data
where NOT REGEXP_LIKE(ip_address,'\.(([0-9])|([1-9][0-9])|([1][0-9][0-9])|(200))$');

Related

Mobile Number should start from 3 in Oracle SQL and also check length should be 10

I have mobile numbers in Oracle table column whose datatype is string
3451111111
923452222222
03451111211
I want SQL statement to select mobile numbers in this form 3451111113 only and check the length = 10.
I want a sub string that starts from character 3 and end at the end of string of length 10. It should neglect the 0, 92 at the beginning and start counting of string from 3 to onwards.
You can use regexp_like():
where regexp_like(number, '^(0|92)?3[0-9]{9}$')
This matches either 0, 92, or nothing at the beginning of the string, then a 3, and then 9 digits.
You can use LIKE:
SELECT *
FROM table_name
WHERE value LIKE '%3_________';
or, if you particularly want strings starting with 3, 03 or 923 then:
SELECT *
FROM table_name
WHERE value LIKE '3_________'
OR value LIKE '03_________'
OR value LIKE '923_________';
Which, for the sample data:
CREATE TABLE table_name ( value ) AS
SELECT '3451111111' FROM DUAL UNION ALL
SELECT '923452222222' FROM DUAL UNION ALL
SELECT '03451111211' FROM DUAL UNION ALL
SELECT '3' FROM DUAL UNION ALL
SELECT '312345678' FROM DUAL UNION ALL
SELECT '3123456789' FROM DUAL UNION ALL
SELECT '31234567890' FROM DUAL;
Both output:
| VALUE |
| :----------- |
| 3451111111 |
| 923452222222 |
| 03451111211 |
| 3123456789 |
db<>fiddle here
To get the last 10 digits:
SUBSTR(phone_num,-10)
To select only values where the last 10 characters are all digits beginning with 3:
select substr(str,-10)
from demo
where regexp_like(str,'3\d{9}$');
The filter will exclude for example 30 bananas (the last 10 characters start with 3, but they are not all digits). It ignores any preceding characters, so for example banana3123456789 would be reported as 3123456789. It's not clear whether you want to exclude that as well.
regexp_substr(str,'3\d{9}$') gives you the portion of the string you want, if you just want to select it without filtering the results.

FETCH DATA BASED ON PARTICULAR STRING

I need to fetch records based on particular type(FFRT-TR= ) and then replace it. For example below are the record types
20017546 FFRT-TR= 3456
TT:SX 2398 FFRT-TR=6532
I need to fetch records which contains FFRT-TR= and then replace the whole the of FFRT-TR=3456 Required Output based on the above examples: 20017546(for 1st example) 2398(for 2nd example)
Please help. Thanks in advance
Something like this? Oracle-ish (you didn't specify the database you use), but - hopefully - you'll be able to rewrite it if necessary.
SQL> with test (col) as
2 (select '20017546 FFRT-TR= 3456' from dual union
3 select 'TT:SX 2398 FFRT-TR=6532' from dual
4 )
5 select
6 col,
7 replace(regexp_substr(col, '\d+ FFRT-TR='), 'FFRT-TR=', '') result
8 from test;
COL RESULT
----------------------- ----------------------------------------------------
20017546 FFRT-TR= 3456 20017546
TT:SX 2398 FFRT-TR=6532 2398
SQL>

Oracle need to remove decimal point

Simple and quick question
If I have column have values in decimals
number
10.20
13.4000
15.987
i Want to remove the decimal from display the output without decimal
number
1020
134000
15987
I have tried
select replace(number, '.','') from table
I got the result but is there any other way to solve it.
Apparently, values you're dealing with are strings, aren't they? Otherwise, you wouldn't have all those trailing zeros.
Anyway, if it happens that these are numbers after all, a little bit of mathematics might produce the desired result. For example:
SQL> with test (num) as
2 (select 10.201 from dual union
3 select 13.4000 from dual union
4 select 15.987 from dual
5 )
6 select num,
7 num * power(10, to_number(length(to_char(num - trunc(num))) - 1)) result
8 from test;
NUM RESULT
---------- ----------
10,201 10201
13,4 134
15,987 15987
SQL>

Comparing values in oracle when one value is partially masked

Here is what I am trying to do in a Oracle SQL query:
I have an account number that is X characters long (Example: 6001055555). I have a table that has part of the same account number but most of the number is masked (Examples: 600##########, 6001######, 600244####).
I am trying to match the number passed in 6001055555 to one of the following values 600##########, 6001######, 600244####.
In this example, account number 6001055555 should return 6001###### (from the above list). I can get to the point where the lengths are the same but am not sure how to address the match - I am looking at using REGEX expressions but am not sure if that' the correct path.
You can use the regular LIKE comparison in this case:
SQL> WITH DATA AS (
2 SELECT '600##########' acct FROM dual UNION ALL
3 SELECT '6001######' acct FROM dual UNION ALL
4 SELECT '600244####' acct FROM dual
5 )
6 SELECT *
7 FROM DATA
8 WHERE '6001055555' LIKE REPLACE (acct, '#', '_');
ACCT
-------------
6001######
We're used to seeing COLUMN LIKE :var but switching terms is also valid (:var LIKE column).
If my understanding is rite, this is what u may be expecting...
select regexp_substr('6001055555',replace('600##########','#'),1) from dual;
If you got any value from this query you may conclude that the account number is matched with the masking values

Comparing list of values against table

I tried to find solution for this problem for some time but without success so any help would be much appreciated. List of IDs needs to be compared against a table and find out which records exist (and one of their values) and which are non existent. There is a list of IDs, in text format:
100,
200,
300
a DB table:
ID(PK) value01 value02 value03 .....
--------------------------------------
100 Ann
102 Bob
300 John
304 Marry
400 Jane
and output I need is:
100 Ann
200 missing or empty or whatever indication
300 John
Obvious solution is to create table and join but I have only read access (DB is closed vendor product, I'm just a user). Writing a PL/SQL function also seems complicated because table has 200+ columns and 100k+ records and I had no luck with creating dynamic array of records. Also, list of IDs to be checked contains hundreds of IDs and I need to do this periodically so any solution where each ID has to be changed in separate line of code wouldn't be very useful.
Database is Oracle 10g.
there are many built in public collection types. you can leverage one of them like this:
with ids as (select /*+ cardinality(a, 1) */ column_value id
from table(UTL_NLA_ARRAY_INT(100, 200, 300)) a
)
select ids.id, case when m.id is null then '**NO MATCH**' else m.value end value
from ids
left outer join my_table m
on m.id = ids.id;
to see a list of public types on your DB, run :
select owner, type_name, coll_type, elem_type_name, upper_bound, precision, scale from all_coll_types
where elem_type_name in ('FLOAT', 'INTEGER', 'NUMBER', 'DOUBLE PRECISION')
the hint
/*+ cardinality(a, 1) */
is just used to tell oracle how many elements are in our array (if not specified, the default will be an assumption of 8k elements). just set to a reasonably accurate number.
You can transform a variable into a query using CONNECT BY (tested on 11g, should work on 10g+):
SQL> WITH DATA AS (SELECT '100,200,300' txt FROM dual)
2 SELECT regexp_substr(txt, '[^,]+', 1, LEVEL) item FROM DATA
3 CONNECT BY LEVEL <= length(txt) - length(REPLACE(txt, ',', '')) + 1;
ITEM
--------------------------------------------
100
200
300
You can then join this result to the table as if it were a standard view:
SQL> WITH DATA AS (SELECT '100,200,300' txt FROM dual)
2 SELECT v.id, dbt.value01
3 FROM dbt
4 RIGHT JOIN
5 (SELECT to_number(regexp_substr(txt, '[^,]+', 1, LEVEL)) ID
6 FROM DATA
7 CONNECT BY LEVEL <= length(txt) - length(REPLACE(txt, ',', '')) + 1) v
8 ON dbt.id = v.id;
ID VALUE01
---------- ----------
100 Ann
300 John
200
One way of tackling this is to dynamically create a common table expression that can then be included in the query. The final synatx you'd be aiming for is:
with list_of_values as (
select 100 val from dual union all
select 200 val from dual union all
select 300 val from dual union all
...)
select
lov.val,
...
from
list_of_values lov left outer join
other_data t on (lov.val = t.val)
It's not very elegant, particularly for large sets of values, but compatibility with a database on which you might have few privileges is very good.