Який би був правильний тип даних для зберігання електронних адрес у PostgreSQL?
Я можу використовувати varchar
(або навіть text
), але мені цікаво, чи є більш конкретний тип даних для електронних листів.
Який би був правильний тип даних для зберігання електронних адрес у PostgreSQL?
Я можу використовувати varchar
(або навіть text
), але мені цікаво, чи є більш конкретний тип даних для електронних листів.
Відповіді:
DOMAIN
sЯ не думаю, що використання citext
(нечутливого до регістру) достатньо [1] . Використовуючи PostgreSQL, ми можемо створити користувацький домен, який по суті є деякими визначеними обмеженнями щодо типу . Ми можемо створити домен, наприклад, над citext
типом або вище text
.
type=email
специфікації HTML5В даний час найбільш правильна відповідь на питання, що таке електронна адреса, вказана в RFC5322 . Ця специфіка є шалено складною [2] , настільки, що все порушує її. HTML5 містить іншу специфікацію електронної пошти ,
Ця вимога є умисним порушенням RFC 5322, який визначає синтаксис адрес електронної пошти, який є одночасно занадто суворим (перед символом "@"), занадто розпливчастим (після символу "@") і занадто розпущеним (дозволяє коментарі , символи пробілу та процитовані рядки у незнайомих для більшості користувачів манерах), щоб бути тут корисними. [...] Наступне регулярне вираження, сумісне з JavaScript і Perl, є реалізацією вищезазначеного визначення.
/^[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])?)*$/
Це, ймовірно, те, що ви хочете, і якщо він досить хороший для HTML5, він, ймовірно, досить хороший для вас. Ми можемо скористатися цим безпосередньо в PostgreSQL. Я також використовую citext
тут (що технічно означає, що ви можете просто згенерувати трохи візуально, видаливши або верхній, або нижній регістр).
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])?)*$' );
Тепер ви можете зробити ...
SELECT 'asdf@foobar.com'::email;
Але не
SELECT 'asdf@foob,,ar.com'::email;
SELECT 'asd@f@foobar.com'::email;
Тому що обидва повертаються
ERROR: value for domain email violates check constraint "email_check"
Тому що це також базується на citext
SELECT 'asdf@foobar.com'::email = 'ASdf@fooBAR.com';
повертає true за замовчуванням.
plperlu
/Email::Valid
Як важлива примітка, існує більш правильний спосіб зробити це, який набагато складніше використовувати plperlu
. Якщо вам потрібен цей рівень правильності, ви не хочете citext
. Email::Valid
Ви можете навіть перевірити, чи є у домену запис MX (наприклад, в документах електронної пошти :: Дійсні)! По-перше, додайте plperlu (потрібен суперрузер).
CREATE EXTENSION plperlu;
Потім створіть функцію , зауважте, що ми позначаємо як 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';
$$;
Потім створіть домен ,
CREATE DOMAIN validemail AS text NOT NULL
CONSTRAINT validemail_check CHECK (valid_email(VALUE));
citext
технічно неправильно. SMTP визначається local-part
як регістр. Але, знову ж таки, це випадок, коли специфіка дурна. Він містить власні кризи ідентичності. Специфікація говорить local-part
(частина до цього @
) "МОЖЕ бути залежною від регістру" ... "ОБОВ'ЯЗКОВО бути поважною до регістру" ... і все ж "використання чутливості регістру місцевих частин поштової скриньки перешкоджає сумісності та не перешкоджає".Жоден із цих регексів не застосовує обмежень по довжині загальної адреси електронної пошти або локальної частини або імен домену. RFC 5322 не визначає жодних обмежень по довжині. Вони випливають з обмежень в інших протоколах, таких як протокол SMTP для фактичного надсилання електронної пошти. RFC 1035 зазначає, що домени повинні містити 63 символи або менше, але не включає це в специфікацію синтаксису. Причина полягає в тому, що справжня звичайна мова не може забезпечити обмеження довжини і одночасно заборонити послідовні дефіси.
a-z
і A-Z
в класах персонажів, і в них?
~
регістру вам потрібно (а) використовувати ~*
нечутливі регістрові регістри, або (b) мати великі та малі літери в char-класі.
citext
«S , ~
здається, нечутливі до регістру для мене, тому я питаю.
Я завжди використовую CITEXT
для електронної пошти, тому що адреса електронної пошти (на практиці) є нечутливою до випадків , тобто John@Example.com - це те саме, що john@example.com.
Також простіше встановити унікальний індекс для запобігання дублікатів порівняно з текстом:
-- 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)));
Порівняння електронних листів також простіше і менш схильне до помилок:
SELECT * FROM address WHERE email = 'JOHN@example.com';
порівняно з:
SELECT * FROM address WHERE lower(email) = lower('JOHN@example.com');
CITEXT
- тип, визначений у стандартному модулі розширення з назвою "citext" , і доступний, ввівши:
CREATE EXTENSION citext;
PS text
і varchar
практично однакові в Postgres, і за використання, text
як можна було очікувати, немає жодного штрафу . Перевірте цю відповідь: Різниця між текстом і варшаром
Я завжди використовую varchar(254)
як адресу електронної пошти не більше 254 символів.
Дивіться https://stackoverflow.com/questions/386294/what-is-the-maximum-length-of-a-valid-email-adreress
Postgresql не має вбудованого типу електронних адрес, хоча я натрапив на певний тип даних.
Крім того, ви можете додати тригер або якусь таку логіку для стандартизації адрес електронної пошти у випадку, якщо ви хочете додати в нього унікальний ключ.
Зокрема, domain
частина адреси електронної пошти (яка має форму local-part
@ domain
є нечутливою до регістру, але local-part
повинна розглядатися як чутлива до регістру. Див. Http://tools.ietf.org/html/rfc5321#section-2.4
Інша думка полягає в тому, що якщо ви хочете зберегти імена та адреси електронної пошти у формі "Joe Bloggs" <joe.bloggs@hotmail.com>
, тоді вам потрібна рядок довжиною більше 254 символів, і ви не зможете значущим чином використовувати унікальне обмеження. Я б цього не робив і пропоную зберігати ім’я та електронну адресу окремо. Досить можлива адреса друку у такому форматі завжди можлива у вашому шарі презентації.
@
).
@
) = 320. Можливо, я його неправильно трактую.
Можливо, вам буде цікаво використовувати чек CONSTRAINT (можливо, простіше, але ви можете відхилити більше, ніж ви хочете, або ви використовуєте FUNCTION, що обговорюється тут і тут . В основному, це все про компроміси між специфікою та простотою реалізації. Цікава тема хоча. PostgreSQL навіть має нативний IP тип адреси, але є проект по pgfoundry для типу даних по електронній пошті тут . Тим НЕ менше, кращий , що я знайшов про це лист домен. Домен краще, ніж обмеження перевірки, тому що якщо ви його зміните, вам доведеться робити це лише один раз у визначенні домену, а не слідувати слідам за таблицями батьків-дочір, змінюючи всі ваші обмеження перевірки. Домени дійсно класні - начебто типи даних, але простіші у виконанні. Я використовував їх у Firebird - Oracle навіть їх не має!