I am working on a project for migrating database from Informix to Postgresql and not able to find a replacement of "MATCHES" in Postgresql. Below is the sql query which I am trying to make work in Postgresql.
SELECT DISTINCT ca.cust_id, a.acct_id FROM cust_acct ca
JOIN acct a on a.acct_id = ca.acct_id
JOIN cust_address cas on ca.cust_id = cas.cust_id
JOIN cust c on ca.cust_id = c.cust_id
JOIN phone cp on c.cust_id = cp.cust_id
WHERE a.recog_id MATCHES '*2972*'
AND cas.last_name MATCHES '*[Q-T]'
AND cas.frst_name MATCHES '[Uu]*'
AND cas.city MATCHES '*X'
AND cas.county MATCHES '*'
AND cp.number MATCHES '*54123'
PROBLEM
I don’t find an expression in Postgresql which I can use to replace "MATCHES" and do no change in java code. Although here, https://www.postgresql.org/docs/current/functions-matching.html#:~:text=9.7.2.%C2%A0SIMILAR%20TO%20Regular%20Expressions%20%23
the documentation says that SIMILAR TO uses POSIX regular expressions, but I don’t see that happening. Even if I replace ‘*’ with ‘%’ , it doesn’t give the same result in Postgresql:
SELECT DISTINCT ca.cust_id, a.acct_id FROM cust_acct ca
JOIN acct a on a.acct_id = ca.acct_id
JOIN cust_address cas on ca.cust_id = cas.cust_id
JOIN cust c on ca.cust_id = c.cust_id
JOIN phone cp on c.cust_id = cp.cust_id
WHERE a.recog_id LIKE '%2972%'
AND cas.last_name LIKE '%[Q-T]'
AND cas.frst_name LIKE '[Uu]%'
AND cas.city LIKE '%X'
AND cas.county LIKE '%'
AND cp.number LIKE '%54123'
I have tried with "SIMILAR TO" and still doesn’t give the expected result.
QUESTIONS
From https://www.ibm.com/docs/en/informix-servers/14.10?topic=condition-matches-operator
MATCHES '*[Q-T]'
-> condition is TRUE for any name that ends with the letters from Q to T. How can I do this in Postgresql?
Is ‘%’ the accepted wildcard in postgresql? and is it be safe to replace all ‘*’ (accepted wildcard for informix) to ‘%’ for regex to work ?
Already tried regex_matches() and that doesn’t work either.
2
Answers
You can do a nearly 1-to-1 translation between
matches
andsimilar to
, but most of the timelike
is sufficient. You only need to usesimilar to
for character classes.Because
similar to
adds additional POSIX regex semantics, uselike
if all you need is wildcards.The translation of your example would be…
See here:
The double tilde (
~~
) operator is a PostgreSQL non-standard extension.(good enough for me), and just to really ram it home:
To check the difference between
LIKE
(ordinary simple match) and~
(a regexp match) (see the fiddle here):populate with some strings:
and then we run the tests – PostgreSQL version first:
Result:
Run the same again with
SIMILAR TO
in place of the PostgreSQL regexp matcher:Result: Same.
However, the Difference is seen when we run:
For the PostgreSQL standard query, we have (entire result not shown for brevity):
and the same line for the
SIMILAR TO
query is:Note:
string.str ~ '^.*[Q-T]$'::text
!=string.str ~ '^(?:.*[Q-T])$'::text
and
string.str ~ '^[U].*$'::text
!=string.str ~ '^(?:[U].*)$'::text
We have a more complex regex for the
SIMILAR TO
constructs as compared with the~
(native PostgreSQL) ones. I don’t know about you, but for me more complex = more resources and/or time – KISS! The extra non-capturing group may not be a huge imposition, but it is worth noting.This was pointed out by @ErwinBrandstetter here
and:
So, migrations are not (for better or worse) simply a question of cut’n’paste. You’ll have to get to know, (appreciate even?), the architecture(s) of your source and target – if it were that simple, we wouldn’t all be making the big bucks! 🙂