PostgreSQLに電子メールアドレスを格納するための適切なデータ型は何ですか?
私はvarchar
(またはtext
)も使用できますが、電子メールにもっと特定のデータ型があるかどうか疑問に思います。
DOMAIN
scitext
(大文字と小文字を区別しない)を使用するだけでは不十分だと思います[1]。 PostgreSQLを使用して カスタムドメインを作成 は、本質的にtypeに対して定義された制約です。たとえば、citext
タイプまたはtext
を介してドメインを作成できます。
type=email
仕様の使用現在、電子メールアドレスとは何であるかという質問に対する最も正解は RFC5322 で指定されています。そのスペックはめちゃくちゃ複雑です[2]everythingがそれを壊してしまうほど。 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 '[email protected]'::email;
だがしかし
SELECT 'asdf@foob,,ar.com'::email;
SELECT 'asd@[email protected]'::email;
それらの両方が戻るので
ERROR: value for domain email violates check constraint "email_check"
これもcitextに基づいているため
SELECT '[email protected]'::email = '[email protected]';
デフォルトではtrueを返します。
plperlu
/ Email::Valid
を使用する重要な注意事項として、plperlu
を使用してこれを行うより正確な方法があります。このレベルの正確さが必要な場合は、しないでくださいcitext
は必要ありません。 Email::Valid
は、ドメインにMXレコードがあるかどうかも確認できます(Email :: Validのドキュメントの例)!まず、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
を大文字と小文字を区別するものとして定義します。しかし、これも the spec が愚かである場合です。それはそれ自身のアイデンティティ危機を含んでいます。仕様はlocal-part
(@
の前の部分)を示しています。 -partsは相互運用性を妨げるのでお勧めしません。」これらの正規表現はどちらも、メールアドレス全体、ローカル部分、またはドメイン名の長さ制限を強制しません。 RFC 5322は長さの制限を指定していません。これらは、実際に電子メールを送信するためのSMTPプロトコルなどの他のプロトコルの制限に起因します。 RFC 1035では、ドメインは63文字以下である必要があると記載されていますが、構文仕様には含まれていません。真の通常の言語では長さの制限を適用できず、連続したハイフンを許可できないためです同時に。
私は常に電子メールにCITEXT
を使用しています。これは、電子メールアドレス (実際には)大文字と小文字が区別されない であるためです。つまり、John @ Example.comは[email protected]と同じです。
また、テキストと比較して、重複を防ぐために一意のインデックスを設定する方が簡単です。
-- 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 = '[email protected]';
と比較して:
SELECT * FROM address WHERE lower(email) = lower('[email protected]');
CITEXT
は 「citext」という名前の標準拡張モジュール で定義されているタイプであり、次のように入力して使用できます。
CREATE EXTENSION citext;
追伸text
とvarchar
はPostgresでは実質的に同じであり、期待どおりにtext
を使用してもペナルティはありません。この回答を確認してください: 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" <[email protected]>
の形式で保存する場合です。この場合、254文字を超える文字列が必要であり、一意制約を有効に使用できません。私はこれを行わず、名前とメールアドレスを別々に保存することをお勧めします。この形式できれいに住所を印刷することは、プレゼンテーション層で常に可能です。
チェックの使用に関心があるかもしれません [〜#〜] constraint [〜#〜] (おそらく簡単ですが、必要以上に拒否する可能性があります。または、説明したFUNCTIONを使用します- here および here 。基本的に、それは具体性と実装の容易さの間のトレードオフに関するものです。興味深いトピックですが、PostgreSQLにはネイティブIPアドレスタイプさえありますが、pgfoundryに関するプロジェクトがあります。電子メールデータタイプ ここ 。ただし、これについて私が見つけた最良のものは電子メール ドメイン です。ドメインを変更すると、ドメイン定義で一度実行して、すべてのチェック制約を変更する親子テーブルの追跡をたどらないでください。ドメインは本当にクールです-データ型のようなものですが、実装が簡単です。Firebirdで使用しました-Oracleにもありませんそれら!