¿Cuál sería el tipo de datos correcto para almacenar direcciones de correo electrónico en PostgreSQL?
Puedo usar varchar
(o incluso text
), pero me pregunto si hay un tipo de datos más específico para los correos electrónicos.
¿Cuál sería el tipo de datos correcto para almacenar direcciones de correo electrónico en PostgreSQL?
Puedo usar varchar
(o incluso text
), pero me pregunto si hay un tipo de datos más específico para los correos electrónicos.
Respuestas:
DOMAIN
sNo creo que usar citext
(mayúsculas y minúsculas) sea suficiente [1] . Usando PostgreSQL podemos crear un dominio personalizado que es esencialmente algunas restricciones definidas sobre un tipo . Podemos crear un dominio, por ejemplo, sobre el citext
tipo o sobre text
.
type=email
especificaciones HTML5Actualmente, la respuesta más correcta a la pregunta de qué es una dirección de correo electrónico se especifica en RFC5322 . Esa especificación es increíblemente compleja [2] , tanto que todo lo rompe. HTML5 contiene una especificación diferente para el correo electrónico ,
Este requisito es una violación intencional de RFC 5322, que define una sintaxis para las direcciones de correo electrónico que es simultáneamente demasiado estricta (antes del carácter "@"), demasiado vaga (después del carácter "@") y demasiado laxa (permitiendo comentarios , caracteres de espacios en blanco y cadenas citadas de maneras desconocidas para la mayoría de los usuarios) para que sean de utilidad práctica aquí. [...] La siguiente expresión regular compatible con JavaScript y Perl es una implementación de la definición anterior.
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
Esto es probablemente lo que desea, y si es lo suficientemente bueno para HTML5, probablemente sea lo suficientemente bueno para usted. Podemos hacer uso de eso directamente en PostgreSQL. También lo uso citext
aquí (lo que técnicamente significa que puede simplemente regexar un poco visualmente eliminando las mayúsculas o minúsculas).
CREATE EXTENSION citext;
CREATE DOMAIN email AS citext
CHECK ( value ~ '^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$' );
Ahora puedes hacer ...
SELECT 'asdf@foobar.com'::email;
Pero no
SELECT 'asdf@foob,,ar.com'::email;
SELECT 'asd@f@foobar.com'::email;
Porque ambos regresan
ERROR: value for domain email violates check constraint "email_check"
Porque esto también se basa en citext
SELECT 'asdf@foobar.com'::email = 'ASdf@fooBAR.com';
devuelve verdadero por defecto.
plperlu
/Email::Valid
Como nota importante, hay un método más correcto para hacerlo que es mucho más complejo de usar plperlu
. Si necesita este nivel de corrección, no lo desea citext
. Email::Valid
¡incluso puede verificar si el dominio tiene un registro MX (ejemplo en documentos de Email :: Valid)! Primero, agregue plperlu (requiere superusuario).
CREATE EXTENSION plperlu;
Luego cree la función , observe que marcamos como IMMUTABLE
:
CREATE FUNCTION valid_email(text)
RETURNS boolean
LANGUAGE plperlu
IMMUTABLE LEAKPROOF STRICT AS
$$
use Email::Valid;
my $email = shift;
Email::Valid->address($email) or die "Invalid email address: $email\n";
return 'true';
$$;
Luego crea el dominio ,
CREATE DOMAIN validemail AS text NOT NULL
CONSTRAINT validemail_check CHECK (valid_email(VALUE));
citext
es técnicamente incorrecto. SMTP define local-part
como mayúsculas y minúsculas. Pero, de nuevo, este es un caso de que la especificación sea estúpida. Contiene sus propias crisis de identidad. La especificación dice local-part
(la parte anterior a @
) "PUEDE ser sensible a mayúsculas y minúsculas" ... "DEBE SER tratada como sensible a mayúsculas y minúsculas" ... y aún así "explotar la mayúsculas y minúsculas de las partes locales del buzón impide la interoperabilidad".Ninguna de estas expresiones regulares impone límites de longitud en la dirección de correo electrónico general o en la parte local o los nombres de dominio. RFC 5322 no especifica ninguna limitación de longitud. Esos se derivan de limitaciones en otros protocolos como el protocolo SMTP para enviar correos electrónicos. RFC 1035 establece que los dominios deben tener 63 caracteres o menos, pero no incluye eso en su especificación de sintaxis. La razón es que un verdadero lenguaje regular no puede imponer un límite de longitud y no permitir guiones consecutivos al mismo tiempo.
a-z
y A-Z
en las clases de personajes?
~
(a) utilizar ~*
mayúsculas y minúsculas o (b) tener las letras mayúsculas y minúsculas en la clase char.
citext
's ~
parece ser sensible a las mayúsculas para mí, es por eso que estoy pidiendo.
Siempre uso CITEXT
para correo electrónico, porque una dirección de correo electrónico no distingue entre mayúsculas y minúsculas , es decir, John@Example.com es igual a john@example.com
También es más fácil configurar un índice único para evitar duplicados, en comparación con el texto:
-- citext
CREATE TABLE address (
id serial primary key,
email citext UNIQUE,
other_stuff json
);
-- text
CREATE TABLE address (
id serial primary key,
email text,
other_stuff json
);
CREATE UNIQUE INDEX ON address ((lower(email)));
Comparar correos electrónicos también es más fácil y menos propenso a errores:
SELECT * FROM address WHERE email = 'JOHN@example.com';
en comparación con:
SELECT * FROM address WHERE lower(email) = lower('JOHN@example.com');
CITEXT
es un tipo definido en un módulo de extensión estándar llamado "citext" , y disponible escribiendo:
CREATE EXTENSION citext;
PD text
y varchar
son prácticamente iguales en Postgres y no hay penalización por usar text
como uno podría esperar. Verifique esta respuesta: Diferencia entre texto y varchar
Siempre uso varchar(254)
como dirección de correo electrónico no puede tener más de 254 caracteres.
Ver https://stackoverflow.com/questions/386294/what-is-the-maximum-length-of-a-valid-email-address
Postgresql no tiene un tipo incorporado para las direcciones de correo electrónico, aunque encontré algún tipo de datos contribuido.
Además, es posible que desee agregar un disparador o alguna lógica para estandarizar las direcciones de correo electrónico en caso de que desee agregar una clave única.
En particular, la domain
parte de la dirección de correo electrónico (que tiene la forma local-part
@ no domain
distingue entre mayúsculas y minúsculas y local-part
debe tratarse como mayúsculas y minúsculas). Consulte http://tools.ietf.org/html/rfc5321#section-2.4
Otra consideración es si desea almacenar nombres y direcciones de correo electrónico en el formulario "Joe Bloggs" <joe.bloggs@hotmail.com>
, en cuyo caso necesita una cadena de más de 254 caracteres y no podrá usar significativamente una restricción única. No haría esto y sugeriría almacenar el nombre y la dirección de correo electrónico por separado. Las direcciones de impresión bonitas en este formato siempre son posibles en su capa de presentación.
@
).
@
) = 320. Quizás lo estoy malinterpretando.
Puede que le interese usar un control CONSTRAINT (posiblemente más fácil, pero puede rechazar más de lo que desea, o usar una FUNCIÓN, discutida aquí y aquí . Básicamente, se trata de compensaciones entre la especificidad y la facilidad de implementación. Tema interesante Sin embargo, PostgreSQL incluso tiene un tipo de dirección IP nativa, pero hay un proyecto en pgfoundry para un tipo de datos de correo electrónico aquí . Sin embargo, lo mejor que encontré sobre esto es un dominio de correo electrónico. El dominio es mejor que una restricción de verificación porque si lo cambia, solo tiene que hacerlo una vez en la definición del dominio y no seguir los rastros de las tablas padre-hijo cambiando todas sus restricciones de verificación. Los dominios son realmente geniales, como los tipos de datos, pero más simples de implementar. Los usé en Firebird: ¡Oracle ni siquiera los tiene!