Quale sarebbe il giusto tipo di dati per memorizzare gli indirizzi e-mail in PostgreSQL?
Posso usare varchar
(o anche text
), ma mi chiedo se esiste un tipo di dati più specifico per le e-mail.
Quale sarebbe il giusto tipo di dati per memorizzare gli indirizzi e-mail in PostgreSQL?
Posso usare varchar
(o anche text
), ma mi chiedo se esiste un tipo di dati più specifico per le e-mail.
Risposte:
DOMAIN
S personalizzatoNon credo che usare citext
(senza distinzione tra maiuscole e minuscole) sia sufficiente [1] . Usando PostgreSQL possiamo creare un dominio personalizzato che è essenzialmente alcuni vincoli definiti su un tipo . Possiamo creare un dominio, ad esempio, sul citext
tipo o su text
.
type=email
specifiche HTML5Attualmente la risposta più corretta alla domanda che cos'è un indirizzo e-mail è specificata in RFC5322 . Quella specifica è follemente complessa [2] , tanto che tutto la rompe. HTML5 contiene una specifica diversa per l'email ,
Questo requisito è una violazione intenzionale di RFC 5322, che definisce una sintassi per gli indirizzi di posta elettronica che è contemporaneamente troppo rigida (prima del carattere "@"), troppo vaga (dopo il carattere "@") e troppo lassista (che consente commenti , i caratteri di spazi bianchi e le stringhe citate in modi non familiari alla maggior parte degli utenti) per essere utili qui. [...] La seguente espressione regolare compatibile con JavaScript e Perl è un'implementazione della definizione sopra.
/^[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])?)*$/
Questo è probabilmente quello che vuoi, e se è abbastanza buono per HTML5, probabilmente è abbastanza buono per te. Possiamo utilizzarlo direttamente in PostgreSQL. Uso anche citext
qui (che tecnicamente significa che puoi semplicemente regex un po 'visivamente rimuovendo il maiuscolo o il minuscolo).
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])?)*$' );
Ora puoi fare ...
SELECT 'asdf@foobar.com'::email;
Ma no
SELECT 'asdf@foob,,ar.com'::email;
SELECT 'asd@f@foobar.com'::email;
Perché entrambi ritornano
ERROR: value for domain email violates check constraint "email_check"
Perché anche questo è basato su citext
SELECT 'asdf@foobar.com'::email = 'ASdf@fooBAR.com';
restituisce true per impostazione predefinita.
plperlu
/Email::Valid
Come nota importante, esiste un metodo più corretto per farlo che è molto più complesso plperlu
. Se hai bisogno di questo livello di correttezza non lo desideri citext
. Email::Valid
può anche verificare se il dominio ha un record MX (esempio nei documenti di Email :: Valido)! Innanzitutto, aggiungi plperlu (richiede un superutente).
CREATE EXTENSION plperlu;
Quindi creare la funzione , notare che contrassegniamo come 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';
$$;
Quindi crea il dominio ,
CREATE DOMAIN validemail AS text NOT NULL
CONSTRAINT validemail_check CHECK (valid_email(VALUE));
citext
è tecnicamente sbagliato. SMTP definisce local-part
la distinzione tra maiuscole e minuscole. Ma, di nuovo, questo è un caso in cui le specifiche sono stupide. Contiene le proprie crisi d'identità. La specifica dice local-part
(la parte prima del @
) "PUO 'essere sensibile al maiuscolo / minuscolo" ... "DEVE ESSERE trattata come sensibile al maiuscolo / minuscolo" ... eppure "lo sfruttamento della distinzione maiuscole / minuscole delle parti locali delle cassette postali impedisce l'interoperabilità ed è scoraggiato".Nessuno di questi regex impone limiti di lunghezza sull'indirizzo e-mail complessivo o sulla parte locale o sui nomi di dominio. RFC 5322 non specifica alcuna limitazione di lunghezza. Questi derivano da limitazioni in altri protocolli come il protocollo SMTP per l'invio effettivo di e-mail. RFC 1035 afferma che i domini devono contenere 63 caratteri o meno, ma non li include nelle specifiche della sintassi. Il motivo è che un vero linguaggio regolare non può imporre un limite di lunghezza e non consentire trattini consecutivi allo stesso tempo.
a-z
e A-Z
nelle classi di caratteri?
~
fa distinzione tra maiuscole e minuscole devi (a) usare la ~*
distinzione tra maiuscole e minuscole o (b) avere le lettere maiuscole e minuscole nella classe di caratteri.
citext
's ~
sembra essere per me maiuscole e minuscole, è per questo che sto chiedendo.
Uso sempre l' CITEXT
e-mail, perché un indirizzo e-mail (in pratica) non fa distinzione tra maiuscole e minuscole , ovvero John@Example.com è uguale a john@example.com.
È anche più semplice impostare un indice univoco per evitare duplicati, rispetto al testo:
-- 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)));
Il confronto delle e-mail è anche più semplice e meno soggetto a errori:
SELECT * FROM address WHERE email = 'JOHN@example.com';
paragonato a:
SELECT * FROM address WHERE lower(email) = lower('JOHN@example.com');
CITEXT
è un tipo definito in un modulo di estensione standard denominato "citext" e disponibile digitando:
CREATE EXTENSION citext;
PS text
e varchar
sono praticamente gli stessi in Postgres e non ci sono penalità per l'utilizzo text
come ci si potrebbe aspettare. Controlla questa risposta: differenza tra text e varchar
Uso sempre varchar(254)
come un indirizzo e-mail non può essere più lungo di 254 caratteri.
Vedi https://stackoverflow.com/questions/386294/what-is-the-ma maximum- length- of-a- valid- email- address
Postgresql non ha un tipo incorporato per gli indirizzi e-mail, anche se mi sono imbattuto in alcuni tipi di dati forniti.
Inoltre, potresti voler aggiungere un trigger o una tale logica per standardizzare gli indirizzi e-mail nel caso in cui desideri aggiungere una chiave univoca su di esso.
In particolare, la domain
parte dell'indirizzo e-mail (che è nella forma local-part
@ non domain
fa distinzione tra maiuscole e minuscole mentre local-part
deve essere trattata come maiuscole / minuscole. Vedi http://tools.ietf.org/html/rfc5321#section-2.4
Un'altra considerazione è se si desidera memorizzare nomi e indirizzi e-mail nel modulo "Joe Bloggs" <joe.bloggs@hotmail.com>
, nel qual caso è necessaria una stringa più lunga di 254 caratteri e non sarà possibile utilizzare in modo significativo un vincolo univoco. Non lo farei e suggerirei di memorizzare il nome e l'indirizzo e-mail separatamente. Indirizzi di stampa piuttosto in questo formato sono sempre possibili nel tuo livello di presentazione.
@
).
@
) = 320. Forse sto interpretando male.
Potresti essere interessato all'utilizzo di un controllo VINCOLO (forse più semplice, ma potresti rifiutare più di quanto vorresti, oppure utilizzare una FUNZIONE, discussa qui e qui . Bascialmente, si tratta di compromessi tra specificità e facilità di implementazione. Argomento interessante però. PostgreSQL ha anche un tipo di indirizzo IP nativa, ma c'è un progetto su pgfoundry per un tipo di dati e-mail qui . Tuttavia, il migliore che ho trovato di questo è una e-mail di dominio. Il dominio è migliore di un vincolo di controllo perché se lo si modifica, è necessario farlo una sola volta nella definizione del dominio e non seguire le tracce delle tabelle padre-figlio modificando tutti i vincoli di controllo. I domini sono davvero fantastici - un po 'come i tipi di dati, ma più semplici da implementare. Li ho usati in Firebird - Oracle non li ha nemmeno!