PostgreSQL에 이메일 주소를 저장하는 가장 좋은 방법은 무엇입니까?


40

PostgreSQL에 이메일 주소를 저장하는 데 적합한 데이터 유형은 무엇입니까?

나는 varchar(또는조차도 text) 사용할 수 있지만 이메일에 대해 더 구체적인 데이터 유형이 있는지 궁금합니다.

답변:


38

사용자 DOMAIN

나는 citext대소 문자를 구분하지 않는 것만으로는 충분 하지 않다고 생각한다 [1] . PostgreSQL을 사용 하여 유형에 대해 정의 된 제약 조건 인 사용자 지정 도메인만들있습니다 . 예를 들어 유형 이상의 도메인을 만들 수 있습니다 .citexttext

HTML5 type=email사양 사용

현재 이메일 주소에 관한 질문에 대한 가장 정확한 답변은 RFC5322에 명시되어 있습니다 . 그 스펙은 엄청나게 복잡하다 [2] . 그래서 모든 것이 그것을 깨뜨린 다. HTML5에는 email대한 다른 사양이 있습니다 .

이 요구 사항은 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 '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있습니다. 이 수준의 정확성이 필요한 경우 원하지 않습니다citext . Email::Valid도메인에 MX 레코드가 있는지 확인할 수도 있습니다 (이메일 문서 :: 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. 이메일 주소 사양은 너무 복잡하여 자체 포함되지도 않습니다. 복잡한 것은 실제로 과소 평가이며 사양을 이해하지 못하는 사람들도 있습니다. . 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) char 클래스에 대문자와 소문자를 사용해야 합니다.
Evan Carroll

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 text와는 varchar사실상 포스트 그레스에서 동일 및 사용에 대한 수수료가없는 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를 참조하십시오.

다른 고려 사항은 이름과 이메일 주소를 양식에 저장하려는 "Joe Bloggs" <joe.bloggs@hotmail.com>경우 254 자보다 긴 문자열이 필요하고 고유 제한 조건을 의미있게 사용할 수 없습니다. 나는 이것을하지 않을 것이며 이름과 이메일 주소를 별도로 저장하는 것이 좋습니다. 이 형식의 주소는 프리젠 테이션 레이어에서 항상 인쇄 할 수 있습니다.


4.5.3.1 에 따르면 . 크기 제한 및 최소값에서 최대 길이는 320 자 (포함 @)입니다.
Andriy M

1
@AndriyM 참조 섹션에는 320이라고 말하는 것이 없습니다. tools.ietf.org/html/rfc5321#section-4.5.3.1.3 은 경로의 최대 길이가 256 자이며 최대 254를 만드는 주변 "<"및 ">"을 포함해야 함을 나타냅니다.
Colin 't Hart

4.5.3.1.1 ( "사용자 이름 또는 기타 로컬 부분의 최대 총 길이는 64 옥텟") 및 4.5.3.1.2 ( "도메인 이름의 최대 총 길이)에 따라 최대 320 점에 도달했습니다. 또는 숫자는 255 옥텟입니다 "). 따라서 64 + 255 + 1 ( @) = 320입니다. 아마도 그것을 잘못 해석하고있을 것입니다.
Andriy M

3
@AndriyM 링크 된 질문에 대한 답변을 읽습니다. 그것은 모든 것을 설명합니다. 320이 아닌 254입니다.
Colin 't Hart

3

당신은 체크 사용에 관심이있을 수있는 제약 조건을 가능한 쉽게 (하지만, 더 당신이 원하는 것보다 거부 할 수도 있고, 당신이 기능이 논의 사용 여기여기 . Bascially, 그것은 특이성 사이의 트레이드 오프에 대해 전부 및 구현의 용이성. 재미있는 주제 PostgreSQL에는 기본 IP 주소 유형도 있지만 pgfoundry에는 전자 메일 데이터 유형에 대한 프로젝트가 있지만 여기에서 내가 찾은 가장 좋은 것은 전자 메일 도메인입니다.. 도메인을 변경하는 경우 도메인 정의에서 한 번만 수행하면되고 모든 검사 제한 조건을 변경하는 상위-하위 테이블을 추적하지 않아도되므로 도메인은 점검 제한 조건보다 낫습니다. 도메인은 데이터 유형과 비슷하지만 구현하기가 더 쉽습니다. Firebird에서 사용했습니다-Oracle에는 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.