ประเภทข้อมูลที่เหมาะสมในการจัดเก็บที่อยู่อีเมลใน 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
ที่นี่ (ซึ่งในทางเทคนิคหมายความว่าคุณสามารถ regex นิดหน่อยด้วยการลบตัวพิมพ์เล็กหรือตัวพิมพ์เล็ก)
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';
ผลตอบแทนจริงตามค่าเริ่มต้น
plperlu
/Email::Valid
plperlu
เป็นบันทึกที่สำคัญมีวิธีการที่ถูกต้องมากขึ้นของการทำเช่นนี้ที่อยู่ห่างไกลที่ซับซ้อนมากขึ้นโดยใช้ ถ้าคุณต้องการระดับของความถูกต้องนี้คุณจะไม่citext
ต้องการ Email::Valid
สามารถตรวจสอบว่าโดเมนมีระเบียน MX (ตัวอย่างในเอกสารของอีเมล :: ถูกต้อง)! ก่อนอื่นให้เพิ่ม plperlu (ต้องการ superuser)
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
(ส่วนก่อนหน้า@
) "อาจต้องตรงตามตัวพิมพ์ใหญ่ - เล็ก" ... "ต้องถือว่าเป็นตัวพิมพ์เล็กและตัวพิมพ์ใหญ่" ... และยัง "ใช้ประโยชน์จากตัวพิมพ์เล็กและตัวพิมพ์เล็กของกล่องจดหมายregexes เหล่านี้ไม่บังคับใช้การจำกัดความยาวของที่อยู่อีเมลโดยรวมหรือส่วนในท้องถิ่นหรือชื่อโดเมน RFC 5322 ไม่ได้ระบุข้อจำกัดความยาวใด ๆ ต้นกำเนิดมาจากข้อ จำกัด ในโปรโตคอลอื่นเช่นโปรโตคอล SMTP สำหรับการส่งอีเมลจริง RFC 1035 ระบุว่าโดเมนต้องมีความยาวไม่เกิน 63 ตัวอักษร แต่ไม่รวมอยู่ในข้อมูลจำเพาะทางไวยากรณ์ เหตุผลคือภาษาจริงที่แท้จริงไม่สามารถบังคับใช้ความยาวสูงสุดและไม่อนุญาตให้ใช้เครื่องหมายขีดกลางต่อเนื่องในเวลาเดียวกัน
a-z
และA-Z
ในชั้นเรียนตัวอักษร?
~
เป็นกรณี ๆ ไปคุณต้อง (a) ใช้~*
case insensitive หรือ (b) มีตัวอักษรพิมพ์ใหญ่และพิมพ์เล็กใน char-class
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
ฉันมักจะใช้varchar(254)
เป็นที่อยู่อีเมลต้องไม่เกิน 254 ตัวอักษร
ดูhttps://stackoverflow.com/questions/386294/what-is-the-maximum-length-of-a-valid-email-address
Postgresql ไม่มีประเภทบิวด์อินสำหรับที่อยู่อีเมล แต่ฉันเจอข้อมูลบางประเภทที่มีส่วน
นอกจากนี้คุณอาจต้องการเพิ่มทริกเกอร์หรือตรรกะบางอย่างเพื่อสร้างที่อยู่อีเมลมาตรฐานในกรณีที่คุณต้องการเพิ่มรหัสที่ไม่ซ้ำกัน
โดยเฉพาะอย่างยิ่งdomain
ส่วนของที่อยู่อีเมล (ซึ่งเป็นรูปแบบlocal-part
@ domain
เป็นตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ในขณะที่local-part
ต้องได้รับการพิจารณาว่าเป็นตัวพิมพ์เล็กและตัวพิมพ์ใหญ่) ดูที่http://tools.ietf.org/html/rfc5321#section-2.4
ข้อควรพิจารณาอีกประการหนึ่งคือถ้าคุณต้องการเก็บชื่อและที่อยู่อีเมลในแบบฟอร์ม"Joe Bloggs" <joe.bloggs@hotmail.com>
ซึ่งในกรณีนี้คุณต้องมีสตริงที่ยาวกว่า 254 อักขระและคุณจะไม่สามารถใช้ข้อ จำกัด ที่มีความหมายได้ ฉันจะไม่ทำเช่นนี้และแนะนำการจัดเก็บชื่อและที่อยู่อีเมลแยกจากกัน ที่อยู่การพิมพ์ที่น่ารักในรูปแบบนี้จะเป็นไปได้เสมอในเลเยอร์การนำเสนอของคุณ
@
)
@
) = 320 บางทีฉันอาจตีความผิด
คุณอาจสนใจใช้เช็คข้อ จำกัด (อาจจะง่ายกว่า แต่อาจปฏิเสธมากกว่าที่คุณต้องการหรือคุณใช้ฟังก์ชั่นที่กล่าวถึงที่นี่และที่นี่โดยพื้นฐานแล้วมันเกี่ยวกับการแลกเปลี่ยนระหว่างความเฉพาะเจาะจงและความง่ายในการใช้งาน แม้ว่า PostgreSQL จะมีประเภทที่อยู่ IP ดั้งเดิม แต่มีโครงการใน pgfoundry สำหรับประเภทข้อมูลอีเมลที่นี่อย่างไรก็ตามสิ่งที่ดีที่สุดที่ฉันพบคือโดเมนอีเมล. โดเมนนั้นดีกว่าข้อ จำกัด การตรวจสอบเพราะถ้าคุณเปลี่ยนคุณต้องทำเพียงครั้งเดียวในการกำหนดโดเมนและไม่ปฏิบัติตามเส้นทางในตารางพ่อแม่และลูกเปลี่ยนแปลงข้อ จำกัด การตรวจสอบทั้งหมดของคุณ โดเมนนั้นเจ๋งจริงๆ - เหมือนประเภทข้อมูล แต่ง่ายต่อการใช้งาน ฉันใช้มันใน Firebird - Oracle ไม่มีแม้กระทั่งพวกเขา!