4

I am using MySQL 8 and have a Regex that needs to return a Regex group from a table column of string data.

DB-Fiddle

Table:

CREATE TABLE `table_name`(
    id_column VARCHAR(300)
);
INSERT INTO `table_name` VALUES
('47099085T'),
('D73654109H'),
('8.30781719e-05'),
('0113:11:19%2000:54:17.042828927Z');

SQL:

 SELECT REGEXP_REPLACE(id_column,
        '[^\\.0-9]([0-9]{8}[TRWAGMYFPDXBNJZSQVHLCKEtrwagmyfpdxbnjzsqvhlcke])', '$1') as id_output
 FROM `table_name`

Regex expected output here (regex101.com)

The Regex contains a group, whose REGEX replace is used to return to the SELECT.

> "47099085T"                         // matches and returns value in quotes.
> D"73654109H"                        // matches and returns value in quotes.
> 8.30781719e-05                      // unmatched
> 0113:11:19%2000:54:17.042828927Z    // unmatched

The MySQL manual states:

  REGEXP_REPLACE(expr, pat, repl[, pos[, occurrence[, match_type]]])

Replaces occurrences in the string expr that match the regular expression specified by the pattern pat with the replacement string repl, and returns the resulting string. If expr, pat, or repl is NULL, the return value is NULL.

Expected outcome:

id_output
47099085T
73654109H

Actual outcome:

id_output
47099085T
73654109H
8.30781719e-05
0113:11:19%2000:54:17.042828927Z

So for the two rows that do not match the sub group, I am expecting the return on the REGEX_REPLACE to be NULL, because there isn't any match. But it instead returns the whole column's data.

Why?

How can I edit the REGEXP to only return matching outcomes?

2
  • Literal dot char does not need in quoting in "not in" list. db-fiddle.com/f/5WAdXxGmwcdCDWH7Bbk85G/4
    – Akina
    Commented Jan 20, 2023 at 16:18
  • 2
    If the pattern doesn't match, nothing is replaced. If nothing is replaced, the output is the same as the input. Simple.
    – hobbs
    Commented Jan 21, 2023 at 14:04

2 Answers 2

4
SELECT id_column,
       REGEXP_REPLACE(id_column, '([^\\d.])(\\d{8}[TRWAGMYFPDXBNJZSQVHLCKEtrwagmyfpdxbnjzsqvhlcke])', '$2') 
FROM `table_name` 
WHERE id_column REGEXP '(^|[^\\d.])(\\d{8}[TRWAGMYFPDXBNJZSQVHLCKEtrwagmyfpdxbnjzsqvhlcke])'

https://www.db-fiddle.com/f/5WAdXxGmwcdCDWH7Bbk85G/4

3
  • Ahh that's brilliant, that works as intended. Thank you!
    – Martin
    Commented Jan 20, 2023 at 16:21
  • Great, You corrected the expression Commented Jan 20, 2023 at 16:23
  • 4
    Don't just post code. Explain what you did, so you actually answer the question.
    – Barmar
    Commented Jan 21, 2023 at 16:32
4

The REPLACE function pretty much does the same thing

Basically, both REPLACE and REGEXP_REPLACE would simply return the original string if there was nothing to replace in the original string.

Just imagine your query written as an UPDATE

UPDATE table_name SET id_column =
REGEXP_REPLACE(id_column,'[^\\.0-9]([0-9]{8}[TRWAGMYFPDXBNJZSQVHLCKEtrwagmyfpdxbnjzsqvhlcke])', '$1') ;

That would be quite destructive if you want REGEXP_REPLACE to return nothing. In light of this, it is a very good thing that both REPLACE and REGEXP_REPLACE would return the original string.

SUGGESTION : Use a WHERE Clause

SELECT REGEXP_REPLACE(id_column, 
'[^\\.0-9]([0-9]{8}[TRWAGMYFPDXBNJZSQVHLCKEtrwagmyfpdxbnjzsqvhlcke])', '$1')
as id_output FROM `table_name` WHERE id_column <>
REGEXP_REPLACE(id_column, 
'[^\\.0-9]([0-9]{8}[TRWAGMYFPDXBNJZSQVHLCKEtrwagmyfpdxbnjzsqvhlcke])', '$1');

The db-fiddle Query is even better WHERE cluase

SELECT id_column
FROM `table_name` 
WHERE id_column REGEXP
'[^\\.0-9][0-9]{8}[TRWAGMYFPDXBNJZSQVHLCKEtrwagmyfpdxbnjzsqvhlcke]'l

What about the MySQL Documentation ???

Your citation of the MySQL Documentation points to the parameters of REGEXP_REPLACE being NULL. It makes no mention of the return value of REGEXP_REPLACE.

UPDATE 2023-01-20 10:50 EST

REGEXP_REPLACE should not return the same value in any instance. The only thing I can think of is if you are running an older version of MySQL 8.0. There is a character set bug mentioned on that documentation page:

Prior to MySQL 8.0.17, the result returned by this function used the UTF-16 character set; in MySQL 8.0.17 and later, the character set and collation of the expression searched for matches is used. (Bug #94203, Bug #29308212)

You might need to experiment with REGEXP_LIKE in the WHERE clause and see (I am not a fan of REGEXP stuff).

3
  • I tried the WHERE clause but the problem is some times the column value is an exact match for the Regex group
    – Martin
    Commented Jan 20, 2023 at 15:41
  • Thanks for the update; my query comes from the DB Fiddle, rather than usage on my own servers -- the DB fiddle only says it uses MySQL 8.0 but doesn't specify exact versioning.
    – Martin
    Commented Jan 20, 2023 at 16:06
  • I updated the db-fiddle with some hash of return values. Please have a look Commented Jan 20, 2023 at 16:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.