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


40

PostgreSQLにメールアドレスを保存するのに適切なデータ型は何ですか?

使用できますvarchar(またはtext)でも、電子メール用のより具体的なデータ型があるのではないかと思います。

回答:


38

カスタムDOMAINs

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

HTML5 type=email仕様の使用

現在、電子メールアドレスとは何かという質問に対する最も正しい答えは、RFC5322で指定されています。その仕様は非常に複雑であるため[2]、非常に複雑であるため、すべてが壊れています。HTML5には、電子メールの異なる仕様が含まれています

この要件は、RFC 5322の意図的な違反です。RFC5322では、同時に厳密すぎる( "@"文字の前)、曖昧すぎる( "@"文字の後)、および緩すぎる(コメントを許可する)電子メールアドレスの構文を定義します、空白文字、およびほとんどのユーザーには馴染みのない方法で引用された文字列)がここで実用的になります。[...]次の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ます。このレベルの正確さが必要な場合は、必要ありませcitextEmail::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大文字と小文字を区別すると定義します。しかし、これも仕様が愚かであるというケースです。独自のアイデンティティー危機が含まれています。仕様ではlocal-part(の前の部分@)「大文字と小文字を区別する可能性があります」...「大文字と小文字を区別する必要があります」...と「メールボックスローカルパーツの大文字と小文字の区別を悪用すると、相互運用性が妨げられます。」
  2. 電子メールアドレスの仕様は非常に複雑であり、自己完結型ではありません。Complexは本当に控えめな表現であり、仕様を作っている人はそれを理解することすらありません。。regular-expression.infoのドキュメントから

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


1
W3.orgリンクが壊れています。ここで代替ソースです:html.spec.whatwg.org/multipage/...は
MaxGabriel

@MaxGabrielに感謝します。すぐに編集パーマを取得できます。そこで修正します。
エヴァンキャロル

キャラクタークラスa-zA-Zキャラクタークラスの両方を使用する理由はありますか?
xehpuk

@xehpuk ~は、大文字と小文字が~*区別されるため、(a)大文字と小文字を区別しないか、(b)文字クラスに大文字と小文字を含める必要があります。
エヴァンキャロル

citextさんは、~私が求めている理由です、私には大文字と小文字を区別しないと思われます。
xehpuk

46

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 textvarcharPostgresで実質的に同じでtextあり、予想どおりに使用してもペナルティはありません。この回答を確認してください:textとvarcharの違い


10

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を参照してください)

もう1つの考慮事項は、フォーム"Joe Bloggs" <joe.bloggs@hotmail.com>に名前と電子メールアドレスを保存する場合です。この場合、254文字より長い文字列が必要であり、一意の制約を有意義に使用することはできません。私はこれを行わず、名前とメールアドレスを別々に保存することをお勧めします。プレゼンテーション層では、この形式で住所をきれいに印刷することが常に可能です。


4.5.3.1によるサイズ制限と最小値、最大長は320文字です(を含む@)。
アンドリーM

1
@AndriyM参照セクションに320と書かれているものは何もありません。とにかく間違っています。tools.ietf.org/html/rfc5321#section-4.5.3.1.3状態パスの最大長は256文字であり、それは最大254を作る「<」と「>」周囲含むことがあること
コリン'tハート

4.5.3.1.1(「ユーザー名または他のローカル部分の最大合計長は64オクテットです」)および4.5.3.1.2(「ドメイン名の最大合計長または数値は255オクテットです」)。したがって、64 + 255 + 1(the @)= 320です。おそらく、私はそれを誤って解釈しています。
アンドリーM

3
@AndriyM私がリンクした質問に対する受け入れられた答えを読んでください。それをすべて説明します。それは間違いなく254だし、いない320
コリン・「Tハート

3

あなたのチェック使用してに興味があるかもしれない制約をおそらくより簡単に(が、あなたがしたいと思います以上拒否することがあります、またはあなたはFUNCTIONを使用し、議論し、ここここ。Bascially、それは特異性と実装の容易さとのトレードオフについてのすべてだ。興味深いトピック。PostgreSQLはさえネイティブIPアドレスの種類がありますが、電子メールのデータ型のpgFoundryに上のプロジェクトがありますが、ここでは。しかし、私はこのことについて発見された最良の電子メールであるドメイン。ドメインはチェック制約よりも優れています。ドメインを変更する場合、ドメイン定義で一度だけ行う必要があり、親子テーブルをたどってすべてのチェック制約を変更する必要がないためです。ドメインは本当にクールです。データ型に似ていますが、実装が簡単です。Firebirdで使用しました-Oracleにはありません!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.