Apa tipe data yang tepat untuk menyimpan alamat email di PostgreSQL?
Saya dapat menggunakan varchar
(atau bahkan text
), tapi saya ingin tahu apakah ada tipe data yang lebih spesifik untuk email.
Apa tipe data yang tepat untuk menyimpan alamat email di PostgreSQL?
Saya dapat menggunakan varchar
(atau bahkan text
), tapi saya ingin tahu apakah ada tipe data yang lebih spesifik untuk email.
Jawaban:
DOMAIN
sSaya tidak berpikir menggunakan citext
(case-insensitive) sudah cukup [1] . Menggunakan PostgreSQL kita dapat membuat domain kustom yang pada dasarnya adalah beberapa batasan yang ditentukan atas suatu jenis . Kami dapat membuat domain misalnya atas citext
jenis, atau lebih text
.
type=email
spec HTML5Saat ini jawaban yang paling benar untuk pertanyaan apa alamat email yang ditentukan dalam RFC5322 . Spek itu sangat kompleks [2] , sedemikian rupa sehingga semuanya merusaknya. HTML5 berisi spesifikasi berbeda untuk email ,
Persyaratan ini adalah pelanggaran yang disengaja terhadap RFC 5322, yang mendefinisikan sintaks untuk alamat email yang secara bersamaan terlalu ketat (sebelum karakter "@"), terlalu kabur (setelah karakter "@"), dan terlalu longgar (memungkinkan komentar , karakter spasi putih, dan string kutipan dalam perilaku yang tidak dikenal oleh sebagian besar pengguna) agar praktis digunakan di sini. [...] Ekspresi reguler yang kompatibel dengan JavaScript dan Perl adalah implementasi dari definisi di atas.
/^[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])?)*$/
Ini mungkin yang Anda inginkan, dan jika cukup baik untuk HTML5, mungkin cukup baik untuk Anda. Kita dapat menggunakannya secara langsung di PostgreSQL. Saya juga menggunakan di citext
sini (yang secara teknis berarti Anda dapat dengan mudah regex sedikit secara visual dengan menghapus huruf besar atau kecil).
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])?)*$' );
Sekarang kamu bisa melakukan ...
SELECT 'asdf@foobar.com'::email;
Tapi tidak
SELECT 'asdf@foob,,ar.com'::email;
SELECT 'asd@f@foobar.com'::email;
Karena keduanya kembali
ERROR: value for domain email violates check constraint "email_check"
Karena ini juga didasarkan pada citext
SELECT 'asdf@foobar.com'::email = 'ASdf@fooBAR.com';
mengembalikan true secara default.
plperlu
/Email::Valid
Sebagai catatan penting, ada metode yang lebih tepat untuk melakukan ini yang menggunakan jauh lebih kompleks plperlu
. Jika Anda membutuhkan tingkat kebenaran yang tidak Anda inginkan citext
. Email::Valid
bahkan dapat memeriksa apakah domain memiliki data MX (contoh dalam dokumen Email :: Valid)! Pertama, tambahkan plperlu (membutuhkan superuser).
CREATE EXTENSION plperlu;
Kemudian buat fungsinya , perhatikan kami tandai di sebagai 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';
$$;
Lalu buat domain ,
CREATE DOMAIN validemail AS text NOT NULL
CONSTRAINT validemail_check CHECK (valid_email(VALUE));
citext
secara teknis salah. SMTP mendefinisikan local-part
sebagai case sensitive. Tapi, sekali lagi, ini adalah kasus spec menjadi bodoh. Ini berisi krisis identitasnya sendiri. Spesifikasinya mengatakan local-part
(bagian sebelum @
) "MUNGKIN case-sensitive" ... "HARUS diperlakukan sebagai case case" ... namun "mengeksploitasi sensitivitas case bagian lokal kotak surat menghambat interoperabilitas dan tidak dianjurkan."Tidak satu pun dari regex ini yang menerapkan batasan panjang pada alamat email keseluruhan atau bagian lokal atau nama domain. RFC 5322 tidak menentukan batasan panjang apa pun. Mereka berasal dari keterbatasan dalam protokol lain seperti protokol SMTP untuk benar-benar mengirim email. RFC 1035 menyatakan bahwa domain harus berukuran 63 karakter atau kurang, tetapi tidak termasuk dalam spesifikasi sintaksisnya. Alasannya adalah bahwa bahasa reguler yang sebenarnya tidak dapat menegakkan batas panjang dan melarang tanda hubung berturut-turut pada saat yang sama.
a-z
dan A-Z
di kelas karakter?
~
case-sensitive Anda harus (a) menggunakan ~*
case-insensitive atau (b) memiliki huruf besar dan kecil di kelas char.
citext
's ~
tampaknya menjadi kasus-sensitif bagi saya, itu sebabnya aku bertanya.
Saya selalu menggunakan CITEXT
untuk email, karena alamat email (dalam praktiknya) tidak sensitif huruf besar , yaitu John@Example.com sama dengan john@example.com.
Lebih mudah mengatur indeks unik untuk mencegah duplikat, dibandingkan dengan teks:
-- 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)));
Membandingkan email juga lebih mudah dan lebih rentan terhadap kesalahan:
SELECT * FROM address WHERE email = 'JOHN@example.com';
jika dibandingkan dengan:
SELECT * FROM address WHERE lower(email) = lower('JOHN@example.com');
CITEXT
adalah jenis yang didefinisikan dalam modul ekstensi standar bernama "citext" , dan tersedia dengan mengetik:
CREATE EXTENSION citext;
PS text
dan varchar
hampir sama di Postgres dan tidak ada penalti untuk digunakan text
seperti yang diharapkan. Periksa jawaban ini: Perbedaan antara teks dan varchar
Saya selalu menggunakan varchar(254)
karena alamat email tidak boleh lebih dari 254 karakter.
Lihat https://stackoverflow.com/questions/386294/what-is-the-maximum-length-of-a-valid-email-address
Postgresql tidak memiliki tipe bawaan untuk alamat email, walaupun saya menemukan beberapa tipe data yang berkontribusi.
Selain itu, Anda mungkin ingin menambahkan pemicu atau logika semacam itu untuk membakukan alamat email jika Anda ingin menambahkan kunci unik di atasnya.
Secara khusus, domain
bagian dari alamat email (yang dalam bentuk local-part
@ domain
tidak peka huruf besar-kecil sedangkan local-part
harus diperlakukan sebagai peka huruf besar-kecil. Lihat http://tools.ietf.org/html/rfc5321#section-2.4
Pertimbangan lain adalah jika Anda ingin menyimpan nama dan alamat email dalam formulir "Joe Bloggs" <joe.bloggs@hotmail.com>
, dalam hal ini Anda membutuhkan string yang lebih panjang dari 254 karakter dan Anda tidak akan dapat menggunakan batasan unik. Saya tidak akan melakukan ini dan menyarankan untuk menyimpan nama dan alamat email secara terpisah. Alamat pencetakan cantik dalam format ini selalu memungkinkan di lapisan presentasi Anda.
@
).
@
) = 320. Mungkin saya salah mengartikannya.
Anda mungkin tertarik menggunakan cek CONSTRAINT (mungkin lebih mudah, tetapi mungkin menolak lebih dari yang Anda inginkan, atau Anda menggunakan FUNGSI, dibahas di sini dan di sini . Pada dasarnya, ini semua tentang pengorbanan antara kekhususan dan kemudahan implementasi. Topik menarik PostgreSQL bahkan memiliki tipe alamat IP asli, tetapi ada proyek pada pgfoundry untuk tipe data email di sini . Namun, yang terbaik yang saya temukan tentang ini adalah domain email. Domain lebih baik daripada batasan cek karena jika Anda mengubahnya, Anda hanya perlu melakukannya sekali dalam definisi domain dan tidak mengikuti jejak menuruni tabel orangtua-anak mengubah semua kendala pemeriksaan Anda. Domain sangat keren - agak seperti tipe data, tetapi lebih mudah diterapkan. Saya menggunakannya di Firebird - Oracle bahkan tidak memilikinya!