AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 68266
Accepted
Adam Matan
Adam Matan
Asked: 2014-06-16 02:32:48 +0800 CST2014-06-16 02:32:48 +0800 CST 2014-06-16 02:32:48 +0800 CST

Qual é a melhor maneira de armazenar um endereço de e-mail no PostgreSQL?

  • 772

Qual seria o tipo de dados correto para armazenar endereços de e-mail no PostgreSQL?

Posso usar varchar(ou até text), mas gostaria de saber se existe um tipo de dado mais específico para emails.

database-design postgresql
  • 6 6 respostas
  • 59469 Views

6 respostas

  • Voted
  1. Best Answer
    Evan Carroll
    2017-03-02T22:46:17+08:002017-03-02T22:46:17+08:00

    DOMAINs personalizados

    Eu não acho que usar citext(não diferencia maiúsculas de minúsculas) é suficiente [1] . Usando o PostgreSQL podemos criar um domínio personalizado que é essencialmente algumas restrições definidas sobre um tipo . Podemos criar um domínio, por exemplo citext, sobre o tipo ou sobre text.

    type=emailUsando a especificação HTML5

    Atualmente, a resposta mais correta para a pergunta o que é um endereço de e-mail é especificada em RFC5322 . Essa especificação é insanamente complexa [2] , tanto que tudo a quebra. HTML5 contém uma especificação diferente para e-mail ,

    Esse requisito é uma violação intencional da RFC 5322, que define uma sintaxe para endereços de e-mail que é simultaneamente muito estrita (antes do caractere "@"), muito vaga (após o caractere "@") e muito relaxada (permitindo comentários , caracteres de espaço em branco e strings entre aspas de maneiras desconhecidas para a maioria dos usuários) para serem de uso prático aqui. [...] A seguinte expressão regular compatível com JavaScript e Perl é uma implementação da definição acima.

    /^[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])?)*$/
    

    Isso é provavelmente o que você quer, e se for bom o suficiente para HTML5, provavelmente é bom o suficiente para você. Podemos fazer uso disso diretamente no PostgreSQL. Eu também uso citextaqui (o que tecnicamente significa que você pode simplesmente o regex visualmente removendo as letras maiúsculas ou minúsculas).

    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])?)*$' );
    

    Agora você pode fazer...

    SELECT '[email protected]'::email;
    

    Mas não

    SELECT 'asdf@foob,,ar.com'::email;
    SELECT 'asd@[email protected]'::email;
    

    Porque ambos retornam

    ERROR:  value for domain email violates check constraint "email_check"
    

    Porque isso também é baseado no citext

    SELECT '[email protected]'::email = '[email protected]';
    

    retorna verdadeiro por padrão.

    Usando plperlu/Email::Valid

    Como uma observação importante, existe um método mais correto de fazer isso que é muito mais complexo usando plperlu. Se você precisa desse nível de correção, você não quer citext. Email::Validpode até verificar se o domínio tem um registro MX (exemplo na documentação de Email::Valid)! Primeiro, adicione plperlu (requer superusuário).

    CREATE EXTENSION plperlu;
    

    Em seguida , crie a função , observe que marcamos como um 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';
    $$;
    

    Em seguida , crie o domínio ,

    CREATE DOMAIN validemail AS text NOT NULL
      CONSTRAINT validemail_check CHECK (valid_email(VALUE));
    

    Notas de rodapé

    1. Usar citexté tecnicamente errado. SMTP define local-partcomo sendo sensível a maiúsculas e minúsculas. Mas, novamente, este é um caso da especificação ser estúpida. Ele contém suas próprias crises de identidade. A especificação diz local-part(a parte antes do @) "Pode diferenciar maiúsculas de minúsculas" ... "Deve ser tratada como sensível a maiúsculas" ... e ainda "explorar a distinção entre maiúsculas e minúsculas das partes locais da caixa de correio impede a interoperabilidade e é desencorajada".
    2. A especificação de um endereço de e-mail é tão complexa que nem é autocontida. Complexo é realmente um eufemismo, aqueles que fazem a especificação nem a entendem. . Dos documentos em regular-expression.info

    Nenhuma dessas regexes impõe limites de comprimento no endereço de e-mail geral ou na parte local ou nos nomes de domínio. A RFC 5322 não especifica nenhuma limitação de comprimento. Esses decorrem de limitações em outros protocolos, como o protocolo SMTP para enviar e-mails. A RFC 1035 afirma que os domínios devem ter 63 caracteres ou menos, mas não inclui isso em sua especificação de sintaxe. A razão é que uma linguagem regular verdadeira não pode impor um limite de comprimento e não permitir hífens consecutivos ao mesmo tempo.

    • 63
  2. hegemon
    2014-08-20T01:07:37+08:002014-08-20T01:07:37+08:00

    Eu sempre uso CITEXTpara email, porque um endereço de email (na prática) não diferencia maiúsculas de minúsculas , ou seja, [email protected] é o mesmo que [email protected].

    Também é mais fácil configurar um índice exclusivo para evitar duplicatas, em comparação com o texto:

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

    Comparar e-mails também é mais fácil e menos propenso a erros:

    SELECT * FROM address WHERE email = '[email protected]';
    

    em comparação com:

    SELECT * FROM address WHERE lower(email) = lower('[email protected]');
    

    CITEXTé um tipo definido em um módulo de extensão padrão chamado "citext" e disponível digitando:

    CREATE EXTENSION citext;
    

    PS texte varcharsão praticamente os mesmos no Postgres e não há penalidade por usar textcomo se pode esperar. Verifique esta resposta: Diferença entre texto e varchar

    • 55
  3. Colin 't Hart
    2014-06-16T03:10:19+08:002014-06-16T03:10:19+08:00

    Eu sempre uso varchar(254)como um endereço de e-mail não pode ter mais de 254 caracteres.

    Consulte https://stackoverflow.com/questions/386294/what-is-the-maximum-length-of-a-valid-email-address

    O Postgresql não tem um tipo embutido para endereços de e-mail, embora eu tenha encontrado alguns tipos de dados contribuídos.

    Além disso, você pode querer adicionar um gatilho ou alguma lógica desse tipo para padronizar os endereços de e-mail caso deseje adicionar uma chave exclusiva a ele.

    Em particular, a domainparte do endereço de e-mail (que tem o formato local-part@ domainnão diferencia maiúsculas de minúsculas, enquanto local-partdeve ser tratada como diferencia maiúsculas de minúsculas. Consulte https://www.rfc-editor.org/rfc/rfc5321#section-2.4

    Outra consideração é se você deseja armazenar nomes e endereços de e-mail no formulário "Joe Bloggs" <[email protected]>; nesse caso, você precisa de uma string com mais de 254 caracteres e não poderá usar significativamente uma restrição exclusiva. Eu não faria isso e sugiro armazenar o nome e o endereço de e-mail separadamente. Endereços de impressão bonitos neste formato são sempre possíveis em sua camada de apresentação.

    • 12
  4. Vérace
    2014-06-16T16:17:22+08:002014-06-16T16:17:22+08:00

    Você pode estar interessado em usar um CHECK CONSTRAINT(possivelmente mais fácil, mas pode rejeitar mais do que gostaria, ou usar uma FUNCTION, discutida aqui e aqui ). Você pode usar um regex com a restrição.

    Você poderia fazer algo assim:

    CREATE TABLE person 
    (
      name TEXT,
      address1 TEXT,
      ...
      ...  other fields...
      ...
      email TEXT
      ...    
      CONSTRAINT 
        proper_email CHECK (email ~* '^[A-Za-z0-9._+%-]+@[A-Za-z0-9.-]+[.][A-Za-z]+$')
    );
    

    O ~*operador corresponde sem distinção entre maiúsculas e minúsculas . O regex( 1 ) pode ser tão complexo quanto você quiser - veja esta resposta magistral que contém uma referência a um regex definitivo com 6.509 caracteres!

    Basicamente, trata-se de compensações entre especificidade e facilidade de implementação. Mesmo assim, tópico interessante. O PostgreSQL tem até um tipo de endereço IP nativo, mas existe um projeto no pgfoundry para um tipo de dados de email aqui .

    No entanto, o melhor que encontrei sobre isso é um domínio de e-mail . O domínio é melhor do que uma restrição de verificação porque se você alterá-lo, você só precisa fazer isso uma vez na definição do domínio e não seguir as trilhas das tabelas pai-filho alterando todas as suas restrições de verificação.

    Os domínios são muito legais - como tipos de dados, mas mais simples de implementar. Eu os usei no Firebird - o Oracle nem os tem!

    1) exemplo descaradamente retirado daqui

    • 3
  5. Irving Juárez
    2022-08-24T17:55:27+08:002022-08-24T17:55:27+08:00

    Não existe um tipo de dados como 'email', mas ainda podemos usar regexp no PostgreSQL. Então, vamos aproveitar.

    A primeira coisa que você gostaria de fazer é:

    1. CREATE EXTENSION citext;Esse tipo de dados é para textos que diferenciam maiúsculas de minúsculas. Portanto, não importa se o texto está em letras maiúsculas ou minúsculas, o Postgres irá usar ambos como o mesmo texto.
    2. Adicione uma restrição CHECK em sua tabela
    CREATE TABLE persons(
        person_id SERIAL PRIMARY KEY,
        person_first_name VARCHAR(50) NOT NULL,
        person_last_name VARCHAR(50),
        person_gender gender_t NOT NULL,
        person_birthdate DATE,
        person_email CITEXT NOT NULL UNIQUE,
        CHECK(
            person_email ~ '^[\w]+\@\w{0,6}\.\w{2,4}$'
        )
    );
    

    Agora aqui, você está aplicando o regexp à sua coluna. person_emailA propósito, o regexp é meio ilustrativo, existem maneiras melhores de validar um email.

    Para o registro, o tipo de dados em person_genderé um tipo personalizado

    CREATE TYPE gender_t AS ENUM('M', 'F');
    
    • 2
  6. Rinat
    2022-10-17T10:35:37+08:002022-10-17T10:35:37+08:00
    • Domínio email.sql- validação mínima básica, mas rápida. Porque a validação será acionada toda vez em uma UPDATEconsulta, mesmo que o valor do campo não tenha sido alterado!
    • Função is_email.sql- validação quase de acordo com a especificação, mas lenta.
    • 0

relate perguntas

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Quais são algumas maneiras de implementar um relacionamento muitos-para-muitos em um data warehouse?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve