Mysql field name within regular expression - sql

I have the following table
Table bots{
ip_address varchar(15),
bot_name varchar(32)
}
Given that some bots have static ips and others won't, the table has entries such as 192.168.0 and 192.168.1.15
Now I have to see if a given ip belongs to a bot. I was thinking something along these lines
SELECT bot_name
FROM bots
WHERE __input_ip__ REGEXP '^ip_address'
but this won't work for the obvious reason that it is looking for a string that starts with ip_address.
So my question is, how can I include a field name within a sql regular expression ?

You might want to consider storing the IP address as an INT UNSIGNED. Also store the netmask so you can tell the difference between a static address and a subnet.
INSERT INTO bots (ipaddress, netmask, bot_name)
VALUES (INET_ATOI('192.168.1.0'), INET_ATOI('255.255.255.0'), 'Wall-E');
Then you can query to see if an input IP address matches:
SELECT bot_name
FROM bots
WHERE __input_ip__ & netmask = ipaddress & netmask;
Using integers for IP addresses instead of CHAR(15) is a common optimization. Even storing the 8 bytes for the IP address and the netmask is little more than half the storage of the CHAR(15). And the bitwise operations are likely to be a lot faster than the regular expression matching, and it's easier to avoid the corner cases like in #Gumbo's comment.

Try this:
SELECT bot_name
FROM bots
WHERE __input_ip__ REGEXP concat('^', replace(ip_address, '.', '\.'))

(This is a response to Andrew's answer but doesn't fit in a comment.)
WHERE __input_ip__ REGEXP concat('^', replace(ip_address, '.', '\.'))
Good plan, except that in MySQL \ is a (non-standard SQL) string literal escape, so to get one in the regexp you'd probably need '\\\.'!
...except in ANSI mode it wouldn't. Argh! To be compatible you'd have to get the backslash another way:
WHERE __input_ip__ REGEXP CONCAT('^', REPLACE(ip_address, '.', CHAR(92, 46)))
Ugh. Maybe better to forget regex and do it with string ops:
WHERE LEFT(__input_ip__, CHAR_LENGTH(ip_address))=__input_ip__

Related

Net functions behave slightly different for IPv4 from IPv6. Why?

I'm using BigQuery to truncate IPv4 & IP46 IP addresses. By that I mean I want to drop the part that might be used to identify a real person.
Here's some demo code:
select *,
NET.IP_TO_STRING(NET.IP_TRUNC(NET.IP_FROM_STRING(v.IPv4Address), 24)),
NET.IP_TO_STRING(NET.IP_TRUNC(NET.IP_FROM_STRING(v.IPv6Address), 64))
from (
select struct(
"254.34.78.20" as `IPV4Address`,
"2a02:c7e:3f0d:e00:48e:abff:d697:9cc2" as `IPv6Address`
) as v
)
It returns:
v
f0_
f1_
{ "IPV4Address": "254.34.78.20", "IPv6Address": "2a02:c7e:3f0d:e00:48e:abff:d697:9cc2" }
254.34.78.0
2a02:c7e:3f0d:e00::
I'd simply like to know why these functions return a 0 for the truncated portion of the IPv4 address but nothing for the truncated portion of the IPv6 address.
I know this isn't really a BigQuery question per se as its more about networks and I suspect BigQuery is just doing what any other such library would do... but interested to know why this is nonetheless. Maybe I'll tag it with IPv6 too
I'd simply like to know why these functions return a 0 for the
truncated portion of the IPv4 address but nothing for the truncated
portion of the IPv6 address.
It is returning 0 for the truncated part of the IPv6 address.
IPv6 addresses can have several forms, but the canonical form requires you to shorten the longest run of 0 fields with a double colon (::). That is at the end of your address 2a02:c7e:3f0d:e00::, and that means it is 2a02:c7e:3f0d:e00:0:0:0:0 properly shortened.

Find Subnet Address given IP Address and Prefix Length in Oracle 12c/ PL SQL

Given IP Address (example: 12.12.12.12/24) return prefix IP address (example: 12.12.12.0).
How can we make these conversions in SQL?
I was trying to string together a method by converting IP address to binary and then ANDing them. There are a tonne of examples in general, nothing that works for PL/SQL. Any help is appreciated.
Here's a way using REGEXP_REPLACE(). The regular expression describes the string, with the 'remembered' part in parentheses. The remembered part is everything up to and including the last period in the string. We don;t want the rest of the string. The replace part of the call replaces with the first remembered part (denoted as \1) followed by the 0.
SELECT REGEXP_REPLACE('12.12.12.12/24', '(.*\.).*', '\10') new_ip
from dual;
NEW_IP
----------
12.12.12.0
1 row selected.

How to remove the domain name from an email address in Oracle

If input like this
as input- abcdxyz#gmail.com & pqrstuv#yahoo.com
and somebody want output like
as output- abcdxyz & pqrstuv
How can I do this using Oracle?
For your case this will do the job:
select regexp_replace('abcdxyz#gmail.com & pqrstuv#yahoo.com','#[a-zA-z0-9.]*','') from dual;
It is based on asumption that domain name contains only digits and a-z chars.
If you know all of the possible email addresses (not likely nor robust), you can use the TRIM function:
http://docs.oracle.com/javadb/10.8.3.0/ref/rreftrimfunc.html
More likely, you'll write your own that "rolls" the characters one at a time until it hits the delimiter. A shortish example to this is here (in the split function of the longer example in the accepted answer):
Is there a function to split a string in PL/SQL?
A more complex example and discussion on performance is here:
https://web.archive.org/web/20170914140540/https://stackoverflow.com/documentation/oracle/1968/splitting-delimited-strings#t=201709141405407224393

Orient-db regex modifiers

I'm working with orient-db database, and I've issues with regex pattern matching. I really need case-insensitive modifier to be present in the request, but somehow it doesn't work as I'm expecting.
Query:
select from UserAccounts where email MATCHES '^ther.*'
Returns as expected matches in lowercase.
Whenever I try to add a modifier, outside delimiters i.e.
select from UserAccounts where email MATCHES '\^ther.*\i'
I get an empty collection. Actually the query returns an empty collection whenever delimiters are present.
If there is no way to attach modifiers I could probably replace each 'alpha' char to an expression in square brackets i.e.
select from UserAccounts where email MATCHES "^[tT][hH][eE][rR].*"
But I'm not really happy with this solution.
Using the Java case-insensitive regex modifier (from Pattern's special constructs) works in OrientDB 1.7.9 - for your example:
select from UserAccounts where email MATCHES '(?i)^ther.*'
(See also: Pattern - Special Constructs)
I've added a comment to the corresponding OrientDB issue as well.
Unfortunately there is no way to specify modifiers for regex in matches operator.
For now the good solution would be to create a custom function, where you can use whole power of JS regexps.
But we definitely should add ability to specify modifiers in MATCHES, could you create a feature request?

Using SQL like for pattern query

I have a PHP function that accepts a parameter called $letter and I want to set the default value of the parameter to a pattern which is "any number or any symbol". How can I do that?
This is my query by the way .
select ID from $wpdb->posts where post_title LIKE '".$letter."%
I tried posting at wordpress stackexchange and they told me to post it here as this is an SQL/general programming question that specific to wordpress.
Thank you! Replies much appreciated :)
In order to match just numbers or letters (I'm not sure exactly what you mean by symbols) you can use the RLIKE operator in MySQL:
SELECT ... WHERE post_title RLIKE '^[A-Za-z0-9]'
That means by default $letter would be [A-Za-z0-9] - this means all letters from a to z (both cases) and numbers from 0-9. If you need specific symbols you can add them to the list (but - has to be first or last, since otherwise it has a special meaning of range). The ^ character tells it to be at the beginning of the string. So you will need something like:
"select ID from $wpdb->posts where post_title RLIKE '^".$letter."%'"
Of course I have to warn you against SQL injection attacks if you build your query like this without sanitizing the input (making sure it doesn't have any ' (apostrophe) in it.
Edit
To match a title that starts with a number just use [0-9] - that means it will match one digit from 0 to 9