match second character regex mysql - mysql

I was watching this mysql course where it the following example was given:
SELECT Name, Continent, Population FROM Country WHERE Name LIKE '_%a' ORDER BY Name;
And they said that '_a%' would match all strings in the Name column whose second character is a. I'm using MariaDB server 10.0.34 on Ubuntu and in my case, the result is quite different. Instead, it shows all strings in the Name column who end in a. Any idea why that is and where the difference exists?
Thanks.

Ummm. A couple of points.
1) those are not regular expressions, those are LIKE comparisons. (Yeah, yeah, to-may-toh, tah-mah-toh, I know.) But we can be precise in our terminology, and avoid confusion and obfuscation.
2) '_%a' and '_a%' are significantly different, as your own observations have revealed
_ underscore matches any one character
% percent matches zero, one or more of any character
a matches the character 'a'
So
LIKE '_a%' matches any single character, followed by an 'a', followed by any number of (zero, one or more) characters
LIKE '_%a' matches any single character, followed by any number of (zero, one or more) any characters, and ending with an 'a'
As a demonstration:
SELECT 'name' LIKE '_a%' -- true - at least two chars, second char is a
, 'name' LIKE '_%a' -- false - at least two chars, last char is a
, 'name' LIKE '_e%' -- false - at least two chars, second char is e
, 'name' LIKE '_%e' -- true - at least two chars, last char is e
Those are LIKE comparisons. To do the equivalent using regular expression, something like this:
SELECT 'name' REGEXP '^.a' -- at least two chars, second char is a
, 'name' REGEXP '^..*a$' -- at least two chars, last char is a
, 'name' RLIKE '^.e' -- at least two chars, second char is e
, 'name' RLIKE '^..*e$' -- at least two chars, last char is e

Related

Mysql LIKE 2nd character and 2nd last character both are 'm'

I try to find query to find a string that 2nd character and 2nd last character both are letter m.
SELECT last_name
FROM employees
WHERE (last_name LIKE '_m%m_' AND LENGTH(last_name) >= '3');
Thanks in advance :)
Why not just OR instead of AND? I don't see the point of AND when your LIKE operator allready rules out names below three characters. You don't need to use regex nor a check for length:
SELECT last_name FROM employees
WHERE last_name LIKE '_m_'
OR last_name LIKE '_m%m_';
The use of OR and LIKE does catch any string that has at least 3 characters.
If you must use regex, try REGEXP operator:
SELECT last_name FROM employees WHERE last_name REGEXP '^.m(.*m)?.$';
Where the pattern means:
^.m - Start-line anchor with a single character and a literal 'm';
(.*m)? - Optional capture group to match 0+ characters upto a literal 'm';
.$ - A single character with end-line anchor.
The benefit of REGEXP is that it's a bit less verbose if you need case-insensitive matching using pattern: '^.[Mm](.*[Mm])?.$'. See an online demo.
If you need all record with second and last character is m you can use the following query:
select * from <table> where <column> like '_m%m'
the _ in the query is a placeholder for one character and % for many characters

How do I covert some column's value by using SQL on MYSQL?

I have a table named Employee in my database, the structure is as shown below:
Id email phone name
1 user#gmail.com +7845690001 Jonney
2 Nortex.zone#gmail.com +7845690781 North
I have some data that I want to mask, for example +7845690001 to +7845690***. Full version as below.
Id email phone name
1 u**r#gmail.com +7845690*** J****y
2 N*********e#gmail.com +7845690*** N***h
I managed to do this for name and phone:
Select CONCAT(MID(phone, 1, LENGTH(phone) - 3), '***') as new_phone,
CONCAT(LEFT(name,1),REPEAT("*",LENGTH(name)-2),RIGHT(name,1)) as new_name from employee.
How can I do this for email?
Finally found the answer:
Select CONCAT(MID(phone, 1, LENGTH(phone) - 3), '***') as new_phone,
CONCAT(LEFT(name,1),REPEAT("*",LENGTH(name)-2),RIGHT(name,1)) as new_name,CONCAT(CONCAT(left(email,1),REPEAT("*",LENGTH(SUBSTRING_INDEX(email, "#", 1))-2),RIGHT(SUBSTRING_INDEX(email, "#", 1),1)),'#',SUBSTRING_INDEX(email,'#',-1)) as new_email from employee
Thanks all. :)
You can work with MySQL's string functions: LEFT(),RIGHT(),LENGTH(), REPEAT(), and SUBSTRING_INDEX() .
I'll just do it for email:
WITH
input(Id,email,phone,name) AS (
SELECT 1 , 'user#gmail.com' ,'+7845690001','Jonney'
UNION ALL SELECT 2 , 'Nortex.zone#gmail.com' ,'+7845690781','North'
)
SELECT
id
, -- the leftmost single character or "email"
LEFT(email,1)
-- repeat "*" for the length of the part of "email" before "#" minus 2
|| REPEAT('*',LENGTH(SUBSTRING_INDEX(email,'#',1))-2)
-- the rightmost single character of the part of "email" before "#"
|| RIGHT(SUBSTRING_INDEX(email,'#',1),1)
-- hard-wire "#"
||'#'
-- the part of "email" from the end of the string back to "#"
||SUBSTRING_INDEX(email,'#',-1)
AS email
FROM input
-- out id | email
-- out ----+-----------------------
-- out 1 | u**r#gmail.com
-- out 2 | N*********e#gmail.com
-- out (2 rows)
You can use CONCAT and SubSTRING functions in mysql.
The email and name has the same feature, use the same thing for name and change digits based your requirement.
SELECT CONCAT(LEFT(`name`, 1),"***",RIGHT(`name`, 1)) as cname, CONCAT(LEFT(`email `, 1),"***",SUBSTRING(`email `, LOCATE("#", `email `)-1, LENGTH(`email `)-LOCATE("#", `email `)-1)) as cemail , CONCAT(LEFT(`phone`, 8),"***") as cphone FROM `test4`
EDITTED -----------------
To fill by the exact number of characters you can use LPAD function. For name you can do:
SELECT CONCAT(LEFT(`name `,1),LPAD(RIGHT(`name `,1),LENGTH(`name `)-1,'*')) FROM `test4`
Use LOCATE and change indexes based on upper query for email.
A REGEXP_REPLACE can also do the trick. Here is how to do it for the email:
SELECT REGEXP_REPLACE(email, '(?!^).(?=[^#]+#)', '*') AS masked_email
FROM Employee;
Explanation:
(?!^) we make sure that the matching character is not at the beginning of the string and that way we skip the first character.
. matches the character to be replaced
(?=[^#]+#) we will stop at a sequence which is any character that is NOT #, then followed by #.
Every single character which is matched between the two will then be replaced with a * (the third parameter) by the function.
For the phone number I will show a much simpler solution:
SELECT REGEXP_REPLACE(phone, '[0-9]{3}$', '***') AS masked_phone
FROM Employee;
[0-9]{3} matches exactly three digits
$ tells that they must be at the end of the string.
We then replace them with three stars. Please note that this solution is assuming that you always store the phone numbers in a way that they always end with three digits. So for example if I enter a phone like "555-55-55-55", nothing will be masked. If you do not always insert the phones normalized in the same format, then you must think about something more complicated (like fetch digit - fetch zero or more non digits - fetch digit - fetch zero or more non digits - fetch digit - end of string, then replace whatever is matched with three *-s). Like this:
SELECT REGEXP_REPLACE(phone, '[0-9][^0-9]*[0-9][^0-9]*[0-9][^0-9]*$', '***') AS masked_phone
FROM Employee;
Here [0-9] means a single digit and [^0-9]* means zero or more non-digits. And of course the same thing can be simplified by grouping the digit and the zero or more non-digits in one group which is then repeated exactly three times:
SELECT REGEXP_REPLACE(phone, '([0-9][^0-9]*){3}$', '***') AS masked_phone
FROM Employee;
And for the name, we can do the following:
SELECT REGEXP_REPLACE(name, '(?!^).(?=.+$)', '*') AS masked_name
FROM Employee;
So again we skip the first character, than match and replace every character until the last character of the string.
IMPORTANT: In the above examples we preserve the length of the strings. If you want higher anonymity, you can fetch the data in groups and then replace a desired group with a single *. For example for the e-mail:
SELECT REGEXP_REPLACE(email, '^(.)(.)+([^#]#.+)$', '\\1*\\3') AS masked_email
FROM Employee;
This will replace john#gmail.dom to j*n#gmail.dom and margareth#gmail.dom to m*h#gmail.dom. So it masked the length as well. Explanation:
^ is the start of the string
(.) is our first group. It it s single character
(.)+ is the second group. It's one or more characters.
([^#]#.+) is our third group. It is a single character which is NOT #, followed by #, then followed by one or more characters (any).
We replace that with \1 (the first group), followed by a single *, followed by \3 (the third group).

MySQL command to get first letter of last name

Hello I have made a dummy table that I am practicing with and I am trying to get the lasts name first letter for example. Aba Kadabra and Alfa Kadabra the last letter of their last name is 'K' so when I was testing some queries such as...
select * from employees
where full_name like 'K%'
select * from employees
where full_name like 'K%'
Neither of these worked. Can anyone tell me the best way to accomplish this?
Because % works that way. See here
So, 'K%' just brings all full_name that start with K.
and '%K' brings all full_name that end with K.
What you need is '% K%', test it please.
MySQL LIKE operator checks whether a specific character string matches
a specified pattern.
The LIKE operator does a pattern matching comparison. The operand to
the right of the LIKE operator contains the pattern and the left hand
operand contains the string to match against the pattern. A percent
symbol ("%") in the LIKE pattern matches any sequence of zero or more
characters in the string. An underscore ("_") in the LIKE pattern
matches any single character in the string. Any other character
matches itself or its lower/upper case equivalent (i.e.
case-insensitive matching). (A bug: SQLite only understands
upper/lower case for ASCII characters by default. The LIKE operator is
case sensitive by default for unicode characters that are beyond the
ASCII range. For example, the expression 'a' LIKE 'A' is TRUE but 'æ'
LIKE 'Æ' is FALSE.)
You can use below query:
select * from table where full_name like '% K%'

Mysql SELECT all rows where char exists in value but not the last one

I need a SELECT query in MYSQL that will retrieve all rows in one table witch field values contain "?" char with one condition: the char is not the last character
Example:
ID Field
1 123??see
2 12?
3 45??78??
Returning rows would then be those from ID 1 and 3 that match the condition given
The only statement I have is:
SELECT *
FROM table
WHERE Field LIKE '%?%'
But, the MySQL query does not solve my problem..
The LIKE expressions also support a wildcard "_" which matches exactly one character.
So you can write an expression like the example below, and know that your "?" will not be the last character in the string. There must be at least one more character.
WHERE intrebare LIKE '%?_%'
Re comment from #JohnRuddell,
Yes, that's true, this will match the string "??" because a "?" exists in a position that is not the last character.
It depends whether the OP means for that to be a match or not. The OP says the string "45??78??" is a match, but it's not clear if they would intend that "4578??" to be a match.
An alternative is to use a regular expression, but this is a little more tricky because you have to escape a literal "?", so it won't be interpreted as a regexp metacharacter. Then also escape the escape character.
WHERE intrebare REGEXP '\\?[^?]'
you can just add an additional where where the last character is not a ?
SELECT *
FROM intrebari
WHERE intrebare LIKE '%?%' AND intrebare NOT LIKE '%?'
you could also do it like this
SELECT *
FROM intrebari
WHERE intrebare LIKE '%?%' AND RIGHT(intrebare,1) <> '?'
DEMO

REGEXP - Select only rows that contain letters and full stop

I've been trying to write this query, I need to select the rows where a column has only letters (a-z) and a full stop.
I tried this but it's not working:
SELECT * FROM table WHERE (c1 REGEXP '[^a-zA-Z\.]') = 0
This one would usually work in PHP.
Try:
SELECT * FROM table WHERE c1 REGEXP '^[a-zA-Z.]+$'
The anchor ^ and $ ensure that you are matching the entire string and not part of it. Next the character class [a-zA-Z.] matches a single upper/lower case letter or a period. The + is the quantifier for one or more repetitions of the previous sub-regex, so in this case it allows us to match one or more of either a period or a upper/lower case letter.
More info on regex usage in MySQL