How can I create a constraint to use a regular expression in postgres?
I recommend using an existing email address parsing module instead of making up your own pattern matching. For example:
CREATE OR REPLACE FUNCTION check_email(email text) RETURNS bool
LANGUAGE plperlu
AS $$
use Email::Address;
my @addresses = Email::Address->parse($_[0]);
return scalar(@addresses) > 0 ? 1 : 0;
$$;
CREATE TABLE emails (
email varchar
CONSTRAINT proper_email CHECK (check_email(email))
);
You can also create a domain and use it as a type when defining table columns, e.g.
CREATE DOMAIN email AS TEXT CHECK (VALUE ~* '^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+[.][A-Za-z]+$');
CREATE TABLE emails (
email email
);
This way you will not need to redefine the regex every time an email containing columns is used in the database.
A better pattern, taken from the OWASP regexp validation library at https://owasp.org/www-community/OWASP_Validation_Regex_Repository is :
/^[a-zA-Z0-9_+&-]+(?:.[a-zA-Z0-9_+&-]+)*@(?:[a-zA-Z0-9-]+.)+[a-zA-Z]{2,7}$/
But this is quite limiting. It does not support comments or quoted names, nor does it support email to an IP address such as name@[10.99.22.4] which is valid. Also valid are UUCP email addresses and a host of others.
https://emailregex.com/ Suggest the following regexp:
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
Though I notice there are no anchors (^$) for this.
CREATE TABLE emails (
email varchar
CONSTRAINT proper_email CHECK (email ~* '^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+[.][A-Za-z]+$')
);
(regex may be incomplete, you can search for regexp for email matching all over the web and pick the one you like best).