web-dev-qa-db-ja.com

PostgreSQLにメールアドレスを保存する最良の方法は何ですか?

PostgreSQLに電子メールアドレスを格納するための適切なデータ型は何ですか?

私はvarchar(またはtext)も使用できますが、電子メールにもっと特定のデータ型があるかどうか疑問に思います。

42
Adam Matan

カスタムDOMAINs

citext(大文字と小文字を区別しない)を使用するだけでは不十分だと思います[1]。 PostgreSQLを使用して カスタムドメインを作成 は、本質的にtypeに対して定義された制約です。たとえば、citextタイプまたはtextを介してドメインを作成できます。

HTML5 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));

脚注

  1. citextの使用は技術的に間違っています。 SMTPはlocal-partを大文字と小文字を区別するものとして定義します。しかし、これも the spec が愚かである場合です。それはそれ自身のアイデンティティ危機を含んでいます。仕様はlocal-part@の前の部分)を示しています。 -partsは相互運用性を妨げるのでお勧めしません。」
  2. メールアドレスの仕様は非常に複雑で、自己完結型ではありません。 Complexは本当に控えめな表現です 仕様を作成するものはそれを理解さえしません。 。 regular-expression.info のドキュメントから

    これらの正規表現はどちらも、メールアドレス全体、ローカル部分、またはドメイン名の長さ制限を強制しません。 RFC 5322は長さの制限を指定していません。これらは、実際に電子メールを送信するためのSMTPプロトコルなどの他のプロトコルの制限に起因します。 RFC 1035では、ドメインは63文字以下である必要があると記載されていますが、構文仕様には含まれていません。真の通常の言語では長さの制限を適用できず、連続したハイフンを許可できないためです同時に。

40
Evan Carroll

私は常に電子メールに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;

追伸textvarcharはPostgresでは実質的に同じであり、期待どおりにtextを使用してもペナルティはありません。この回答を確認してください: textとvarcharの違い

47
hegemon

私は常に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文字を超える文字列が必要であり、一意制約を有効に使用できません。私はこれを行わず、名前とメールアドレスを別々に保存することをお勧めします。この形式できれいに住所を印刷することは、プレゼンテーション層で常に可能です。

10
Colin 't Hart

チェックの使用に関心があるかもしれません [〜#〜] constraint [〜#〜] (おそらく簡単ですが、必要以上に拒否する可能性があります。または、説明したFUNCTIONを使用します- here および here 。基本的に、それは具体性と実装の容易さの間のトレードオフに関するものです。興味深いトピックですが、PostgreSQLにはネイティブIPアドレスタイプさえありますが、pgfoundryに関するプロジェクトがあります。電子メールデータタイプ ここ 。ただし、これについて私が見つけた最良のものは電子メール ドメイン です。ドメインを変更すると、ドメイン定義で一度実行して、すべてのチェック制約を変更する親子テーブルの追跡をたどらないでください。ドメインは本当にクールです-データ型のようなものですが、実装が簡単です。Firebirdで使用しました-Oracleにもありませんそれら!

3
Vérace