Grupos exclusivos de desconto no WhatsApp — Faca parte agora! Participar

CNPJ alfanumérico no banco: MySQL e PostgreSQL

Como adaptar a coluna de CNPJ no MySQL e no PostgreSQL ao formato alfanumérico: ALTER TABLE para VARCHAR, cuidados com comparação, ordenação, índices e máscara do formulário.

CNPJ alfanumérico no banco: MySQL e PostgreSQL

Guardar CNPJ alfanumérico no banco de dados começa com uma decisão simples: a coluna precisa ser texto, nunca número. Se hoje você usa INT, BIGINT ou ZEROFILL, o novo formato vai quebrar — as letras das 12 primeiras posições não cabem em campo numérico. Este tutorial mostra o ALTER TABLE certo para MySQL e PostgreSQL, os cuidados com comparação, ordenação e índices, e como ajustar a máscara do formulário.

O que muda no CNPJ alfanumérico

A partir de julho de 2026, o novo CNPJ alfanumérico mantém as 14 posições e a mesma máscara XX.XXX.XXX/XXXX-DD, mas as 12 primeiras posições (raiz + ordem) passam a aceitar letras maiúsculas A–Z além dos dígitos 0–9. Os dois últimos caracteres (dígitos verificadores) continuam numéricos. Os CNPJs numéricos atuais não mudam e seguem válidos, então seu banco precisa armazenar e comparar os dois formatos ao mesmo tempo. Para o panorama completo, veja o nosso guia de implementação do CNPJ alfanumérico.

O erro nº 1: guardar CNPJ como número

O problema mais comum em sistemas brasileiros é a coluna de CNPJ ter sido criada como inteiro. Funcionava enquanto o CNPJ era só dígito, mas tinha bugs silenciosos (zeros à esquerda some, 00.000.123/... vira 123) e agora simplesmente não aceita letras. Um CNPJ ABC1234D56... gravado em BIGINT resulta em 0, erro de truncamento ou exceção, dependendo do banco.

Migrando a coluna: ALTER TABLE

A recomendação é guardar o CNPJ sem máscara, com 14 caracteres, sempre em maiúsculas. Se você optar por gravar com máscara, use largura 18. Abaixo, o ALTER TABLE para cada banco — rode antes de julho de 2026, num horário de baixo tráfego, e com backup feito.

SQL
-- guarde sem máscara, 14 caracteres, sempre maiúsculo
ALTER TABLE clientes MODIFY cnpj VARCHAR(14) NULL;   -- MySQL
ALTER TABLE clientes ALTER COLUMN cnpj TYPE varchar(14);  -- PostgreSQL

No MySQL, MODIFY reescreve a definição inteira da coluna — repita os atributos que quer manter (por exemplo NULL/NOT NULL). No PostgreSQL, se a coluna atual for inteira, o TYPE varchar(14) precisa de uma conversão explícita; use USING para não perder os dados existentes:

SQL
-- PostgreSQL: convertendo de inteiro para texto sem perder o que já existe
ALTER TABLE clientes
  ALTER COLUMN cnpj TYPE varchar(14)
  USING lpad(cnpj::text, 14, '0');

Comparação, ordenação e índices

Depois de virar texto, ajuste as consultas. Buscas devem usar a string normalizada — sempre maiúscula e sem máscara — para casar com o que está gravado:

SQL
-- certo: compara como texto, já normalizado pela aplicação
SELECT * FROM clientes WHERE cnpj = 'ABC1234D5601' || '...';

-- errado: nunca compare como número
-- SELECT * FROM clientes WHERE cnpj = 12345678000190;

A ordenação passa a ser alfabética (lexicográfica), o que é o esperado para um identificador alfanumérico — não tente reproduzir ordem numérica. Para o índice, um VARCHAR(14) indexa normalmente e a busca por igualdade continua rápida. Se a sua coluna pode receber valores em caixas diferentes por causa de dados legados, garanta a normalização na escrita (gravar sempre em maiúsculas) ou crie um índice funcional sobre UPPER(cnpj) no PostgreSQL:

SQL
-- PostgreSQL: índice funcional para buscas case-insensitive
CREATE INDEX idx_clientes_cnpj_upper ON clientes (UPPER(cnpj));

-- MySQL: a melhor estratégia é gravar já em maiúsculas
CREATE INDEX idx_clientes_cnpj ON clientes (cnpj);

Ajustando a máscara e a validação no formulário

No front-end, o erro espelha o do banco: máscaras e validações que só aceitam dígitos. Troque type="number" por type="text", force maiúsculas com CSS e use uma expressão regular que aceite letras nas 12 primeiras posições. Nunca use \d para a base inteira.

HTML
<input
  type="text"
  name="cnpj"
  maxlength="18"
  inputmode="text"
  style="text-transform: uppercase"
  placeholder="XX.XXX.XXX/XXXX-DD"
>

Na validação do lado do cliente, use o padrão com máscara ou só os 14 caracteres. Letras nas 12 primeiras, dígitos nos dois verificadores:

JavaScript
// com máscara: XX.XXX.XXX/XXXX-DD
const FORMATO_MASCARA = /^[A-Z0-9]{2}\.[A-Z0-9]{3}\.[A-Z0-9]{3}\/[A-Z0-9]{4}-\d{2}$/;

// só caracteres (o que vai pro banco): 12 alfanuméricos + 2 dígitos
const FORMATO_LIMPO = /^[A-Z0-9]{12}\d{2}$/;

// normalize SEMPRE antes de gravar: maiúsculas, sem máscara
const normalizar = (s) => (s || '').toUpperCase().replace(/[^A-Z0-9]/g, '');

Repare que a diferença para o código antigo é trocar \d por [A-Z0-9] nas 12 primeiras posições e aplicar toUpperCase() na normalização. O valor que chega ao banco é o resultado de normalizar(): 14 caracteres, maiúsculos, sem pontuação.

Como testar

Checklist de migração
  • Trocar todas as colunas de CNPJ de INT/BIGINT/ZEROFILL para VARCHAR(14) (ou 18 com máscara).
  • Rodar o UPDATE de normalização: maiúsculas e sem máscara nos dados existentes.
  • Remover comparações numéricas (= 12345) e qualquer ORDER BY que assuma ordem numérica.
  • Garantir gravação em MAIÚSCULAS na aplicação; criar índice funcional UPPER(cnpj) se houver dados em caixas diferentes.
  • Atualizar o formulário: type="text", text-transform: uppercase, regex com [A-Z0-9] em vez de \d.
  • Auditar integrações, NF-e e contratos de API para aceitar letras; manter a convivência com os CNPJs numéricos atuais.

Para gerar massa de teste e popular o banco, use o nosso gerador de CNPJ alfanumérico e confira cada valor no validador de CNPJ alfanumérico.

CNPJTipoEsperado
12.ABC.345/01DE-35Alfanumérico (filial)válido
XP.TO1.234/0001-20Alfanumérico (matriz)válido
9F.8E7.D6C/0001-36Alfanumérico (matriz)válido
A1.B2C.3D4/E5F6-68Alfanumérico (filial)válido
ZZ.ZZ0.001/AAAA-41Alfanuméricoválido
11.222.333/0001-81Numérico clássicoválido
12.ABC.345/01DE-34DV incorretoinválido

Perguntas frequentes

Posso continuar usando coluna numérica e converter na aplicação?

Não. Um CNPJ alfanumérico como 12ABC34501DE35 não é representável em INT ou BIGINT — a conversão descarta as letras ou estoura. A única coluna correta é texto (VARCHAR(14) sem máscara), e a normalização (maiúsculas, sem pontuação) deve acontecer na aplicação antes de gravar.

VARCHAR(14) ou VARCHAR(18)?

Use VARCHAR(14) se guardar sem máscara, que é a recomendação: são exatamente 14 posições. Se você precisa armazenar com a máscara XX.XXX.XXX/XXXX-DD, aí são 18 caracteres. Guardar sem máscara facilita índices, comparações e a convivência com os CNPJs numéricos atuais.

Como faço a validação do CNPJ antes de gravar?

A validação (módulo 11 com ASCII − 48) roda na aplicação, não no banco. Veja as funções prontas em PHP e JavaScript — elas já normalizam para maiúsculas e devolvem a string de 14 caracteres pronta para o VARCHAR.

Os CNPJs numéricos que já estão no banco continuam válidos?

Continuam. Os numéricos atuais não mudam e seguem em uso ao lado dos novos. Como a coluna vira texto, ela aceita os dois formatos sem qualquer perda — basta garantir que comparações e índices tratem o campo como string.

Fontes: Receita Federal (IN RFB 2.229/2024) e nota técnica do Serpro sobre o CNPJ alfanumérico.

Assistente PP
Assistente PP
Online agora
Powered by Primeira Solução