SQL Tipos de Dados

Todo valor guardado num banco tem um tipo: é um número inteiro, um número com casas decimais, um texto, um arquivo… Esta página reúne, num lugar só, tudo o que você precisa consultar sobre tipos: como o SQLite guarda cada valor, o que ele faz com o nome de tipo que você escreve no CREATE TABLE, as tabelas rígidas (STRICT) e o nome de cada tipo no PostgreSQL, no MySQL e no SQL Server. As explicações passo a passo estão nas aulas Tipos de Dados e Os Tipos no SQLite.

Como ler esta página
  • Os quadros "Resultado" rodam de verdade no SQLite 3.50.4 do seu navegador, com o banco da Loja Aurora.
  • Os tamanhos e limites dos outros bancos foram conferidos na documentação oficial de cada um (PostgreSQL e SQL Server nas versões atuais, MySQL 8.4). Os trechos de código deles não rodam aqui e estão marcados como ilustrativos.
  • typeof(x) é a função do SQLite que diz a classe de um valor. Ela aparece em quase todos os exemplos.

As cinco classes de armazenamento do SQLite

No SQLite, o tipo pertence ao valor, e não à coluna. Cada valor guardado é de uma destas cinco classes (em inglês, storage classes):

ClasseO que guardaComo se escrevetypeof() devolveTamanho (documentação do SQLite)
NULL"Sem valor"NULLnull—
INTEGERNúmero inteiro com sinal42, -7, 0integer0, 1, 2, 3, 4, 6 ou 8 bytes, conforme o tamanho do número
REALNúmero com casas decimais (aproximado)4.9, 1.0, 1e3realSempre 8 bytes (ponto flutuante IEEE)
TEXTTexto'Teresina' (aspas simples)textO tamanho do texto, na codificação do banco (UTF-8 na Loja Aurora)
BLOBBytes guardados exatamente como chegaram (uma imagem, um arquivo)x'CAFE' (bytes em hexadecimal)blobO tamanho dos bytes
SELECT typeof(NULL), typeof(42), typeof(4.9), typeof('Teresina'), typeof(x'CAFE');

Na Loja Aurora, cada coluna guarda sempre a mesma classe, porque os dados foram gravados com cuidado. A exceção são as colunas com campos vazios: a coluna email de clientes tem valores text e três null.

SELECT DISTINCT typeof(email) FROM clientes;

A afinidade: o tipo que você escreve no CREATE TABLE

O nome de tipo de uma coluna (INTEGER, VARCHAR(100), DATE…) não obriga nada no SQLite comum: ele vira uma afinidade, a classe que a coluna "prefere" e para a qual ela tenta converter os valores que chegam. A documentação do SQLite define a afinidade por estas regras, nesta ordem:

RegraSe o nome do tipo…AfinidadeExemplos da documentação
1contém INTINTEGERINT, INTEGER, TINYINT, SMALLINT, MEDIUMINT, BIGINT, UNSIGNED BIG INT, INT2, INT8
2contém CHAR, CLOB ou TEXTTEXTCHARACTER(20), VARCHAR(255), VARYING CHARACTER(255), NCHAR(55), NATIVE CHARACTER(70), NVARCHAR(100), TEXT, CLOB
3contém BLOB, ou não tem tipoBLOB (nenhuma conversão)BLOB, coluna sem tipo
4contém REAL, FLOA ou DOUBREALREAL, DOUBLE, DOUBLE PRECISION, FLOAT
5nenhuma das anterioresNUMERICNUMERIC, DECIMAL(10,5), BOOLEAN, DATE, DATETIME
  • Os números entre parênteses são ignorados: a documentação diz que o SQLite não impõe limite de tamanho por causa deles. VARCHAR(2) aceita 'Piauí'.
  • DATE, DATETIME e BOOLEAN não criam nada especial: caem na regra 5, afinidade NUMERIC.
  • A ordem das regras importa: FLOATING POINT tem INT no meio ("poINT") e vira INTEGER pela regra 1.

O que cada afinidade faz com o valor que chega

AfinidadeChega um texto que parece número ('19.90')Chega um númeroChega um texto qualquer ('sim')
TEXTFica textoVira textoFica texto
NUMERICVira número: inteiro se der, senão realFica número (3.0 vira o inteiro 3)Fica texto
INTEGERIgual à NUMERICIgual à NUMERICFica texto
REALVira realVira real (42 vira 42.0)Fica texto
BLOBFica como chegouFica como chegouFica como chegou

Uma tabela com os nomes de tipo dos outros bancos, para ver a afinidade agindo. O '19.90' virou o número 19.9; o 'sim' continuou texto na coluna BOOLEAN; a data continuou texto; e o VARCHAR(2) guardou as cinco letras de 'Piauí':

CREATE TABLE t (uf VARCHAR(2), preco DECIMAL(10,2), ativo BOOLEAN, dia DATE);
INSERT INTO t VALUES ('Piauí', '19.90', 'sim', '2026-10-14');
SELECT uf, typeof(uf), preco, typeof(preco), ativo, typeof(ativo), dia, typeof(dia)
FROM t;

Tabelas STRICT: os seis tipos aceitos

Com a palavra STRICT no fim do CREATE TABLE, o SQLite passa a recusar valores do tipo errado. Toda coluna precisa de tipo, e só valem estes nomes:

TipoAceita
INT ou INTEGERInteiros, e o que vira inteiro sem perder nada ('5', 3.0)
REALNúmeros; um inteiro vira real
TEXTTexto; um número vira texto
BLOBSó bytes
ANYQualquer valor, guardado exatamente como chegou
CREATE TABLE s (n INTEGER, t TEXT, r REAL, b BLOB, a ANY) STRICT;
INSERT INTO s VALUES ('5', 42, 42, x'CAFE', '5');
SELECT n, typeof(n), t, typeof(t), r, typeof(r), typeof(b), a, typeof(a)
FROM s;

O '5' virou o inteiro 5 na coluna INTEGER, mas continuou o texto '5' na coluna ANY. O 42 virou texto em t e real em r. As mensagens de quando o valor não serve estão em Erros comuns; a aula completa é Os Tipos no SQLite.


Datas, horas e booleanos no SQLite

O SQLite não tem classe própria para datas nem para verdadeiro/falso. A documentação dele recomenda estas formas:

DadoClasse usadaFormatoExemplo
Data e horaTEXTISO 8601: 'AAAA-MM-DD HH:MM:SS.SSS''2026-10-14', '2026-10-14 15:30:00'
Data e horaREALDia juliano: dias desde o meio-dia de 24/11/4714 a.C. (em Greenwich)2461327.5
Data e horaINTEGERTempo Unix: segundos desde 1970-01-01 00:00:00 UTC1791936000
BooleanoINTEGER1 = verdadeiro, 0 = falso; TRUE e FALSE (desde a versão 3.23.0) são só outros nomes para 1 e 0vip = 1, vip = TRUE

A Loja Aurora usa a primeira forma: datas em texto ISO, que ordenam e comparam certo. As funções de data convertem entre as três formas:

SELECT julianday('2026-10-14'), unixepoch('2026-10-14'),
       date(2461327.5), date(1791936000, 'unixepoch');
SELECT TRUE, FALSE, typeof(TRUE);

Mais sobre datas em Datas e Horas e Funções de Data.


Funções para ver e trocar o tipo

EscritaO que fazExemploResultado
typeof(x)A classe do valor: null, integer, real, text ou blobSELECT typeof(preco) FROM produtos WHERE id = 1;real
CAST(x AS INTEGER)Converte para inteiro; corta as casas decimaisSELECT CAST(3.99 AS INTEGER);3
De texto: lê os algarismos do começoSELECT CAST('12abc' AS INTEGER);12
Texto sem número nenhum vira 0, sem erroSELECT CAST('abc' AS INTEGER);0
CAST(x AS REAL)Converte para realSELECT CAST('4.9' AS REAL);4.9
CAST(x AS TEXT)Converte para textoSELECT typeof(CAST(42 AS TEXT));text
pragma_table_info('tabela')Lista as colunas de uma tabela, com o tipo declarado (coluna type)SELECT name, type FROM pragma_table_info('produtos');7 linhas: id|INTEGER, nome|TEXT…
SELECT CAST('42' AS INTEGER), CAST('4.9' AS REAL), CAST(42 AS TEXT),
       typeof(CAST(42 AS TEXT)), CAST('12abc' AS INTEGER),
       CAST('abc' AS INTEGER), CAST(3.99 AS INTEGER);

Experimente: troque os valores dentro de typeof() e de CAST() e veja a classe de cada um. Teste typeof('42') × typeof(42), typeof(1.0), typeof(7 / 2) e typeof(7 / 2.0).

SELECT typeof('42'), typeof(42), typeof(1.0), typeof(7 / 2), typeof(7 / 2.0);

Os tipos da Loja Aurora

Todas as colunas do banco das aulas, com o tipo declarado no CREATE TABLE. A Loja Aurora usa só três nomes: INTEGER, REAL e TEXT.

SELECT m.name AS tabela, p.name AS coluna, p.type AS tipo
FROM sqlite_schema AS m, pragma_table_info(m.name) AS p
WHERE m.type = 'table'
ORDER BY m.name, p.cid;
TipoColunas da Loja AuroraPor quê
INTEGERid, os …_id, estoque, quantidade, vip, descontinuadoContagens, números de ficha e sim/não (0 ou 1)
REALpreco, preco_unitario, frete, salarioValores com centavos (arredonde com round() nas contas)
TEXTnomes, email, cidade, estado, telefone, data, nascimento, entregue_emTextos e datas no formato ISO

Missão: a consulta lista as colunas da tabela produtos com o tipo de cada uma. Mude-a para listar as colunas da tabela clientes.

SELECT name, type FROM pragma_table_info('produtos');
SELECT name, type FROM pragma_table_info('clientes');

Limites e surpresas dos números no SQLite

CasoExemploResultadoO que acontece
Maior inteiro (8 bytes)SELECT 9223372036854775807;9223372036854775807263 − 1
Passou do limiteSELECT 9223372036854775807 + 1;9.22337203685478e+18A conta vira real (aproximado), sem erro
Divisão de inteirosSELECT 7 / 2;3Inteiro dividido por inteiro dá inteiro
Com um real na contaSELECT 7 / 2.0;3.5Basta um dos lados ser real
Decimais aproximadosSELECT 0.1 + 0.2 = 0.3;0O real guarda um valor muito próximo, não exato
ArredondandoSELECT round(0.1 + 0.2, 2);0.3Arredonde antes de comparar
SELECT 9223372036854775807 + 1, 7 / 2, 7 / 2.0, 0.1 + 0.2 = 0.3, round(0.1 + 0.2, 2);

Mais em Funções Numéricas.


Os equivalentes nos outros bancos

PostgreSQL, MySQL e SQL Server são rígidos: o tipo é da coluna, e um valor que não serve dá erro. Cada um tem os seus nomes. A tabela abaixo põe lado a lado o nome mais usado para cada dado. Nomes, tamanhos e limites conferidos na documentação oficial de cada banco.

DadoSQLitePostgreSQLMySQLSQL Server
Inteiro pequenoINTEGERsmallint (2 bytes)TINYINT (1 byte), SMALLINT (2 bytes)tinyint (1 byte, só 0 a 255), smallint (2 bytes)
InteiroINTEGERinteger ou int (4 bytes)INT (4 bytes)int (4 bytes)
Inteiro grandeINTEGER (até 8 bytes)bigint (8 bytes)BIGINT (8 bytes)bigint (8 bytes)
Decimal exato (dinheiro)aceita DECIMAL(p,s), mas guarda aproximado (afinidade NUMERIC)numeric(p,s) ou decimal(p,s)DECIMAL(M,D): até 65 algarismos, até 30 depois da vírguladecimal(p,s) ou numeric(p,s): até 38 algarismos
Aproximado simples— (o REAL tem sempre 8 bytes)real (4 bytes, cerca de 6 algarismos)FLOAT (precisão simples, cerca de 7 casas)real (4 bytes, 7 algarismos)
Aproximado duploREAL (8 bytes)double precision (8 bytes, 15 algarismos)DOUBLE (precisão dupla, cerca de 15 casas)float (8 bytes, 15 algarismos)
Texto de tamanho fixoTEXTchar(n)CHAR(M), M de 0 a 255 letraschar(n), n de 1 a 8.000 bytes
Texto com limiteTEXT (o n é ignorado)varchar(n)VARCHAR(M), M até 65.535 (limitado pelo tamanho da linha)varchar(n), n de 1 a 8.000 bytes; nvarchar(n), n de 1 a 4.000 pares de bytes
Texto longoTEXTtextTEXT (65.535 bytes), MEDIUMTEXT, LONGTEXT (4 GB)varchar(max) ou nvarchar(max) (2 GB)
DataTEXT 'AAAA-MM-DD'dateDATE, de 1000-01-01 a 9999-12-31date, de 0001-01-01 a 9999-12-31
Data e horaTEXT 'AAAA-MM-DD HH:MM:SS'timestamp; com fuso: timestamptzDATETIME (1000 a 9999); TIMESTAMP (1970 a 2038, em UTC)datetime2, de 0001 a 9999
Verdadeiro/falsoINTEGER 0/1booleanBOOLEAN = TINYINT(1)bit (1, 0 ou NULL)
BinárioBLOBbyteaBLOB (65.535 bytes)varbinary(n), n até 8.000; varbinary(max)

As faixas dos inteiros

TamanhoMenor valorMaior valorNomes
1 byte-128 (MySQL) ou 0 (SQL Server)127 (MySQL) ou 255 (SQL Server)TINYINT (MySQL), tinyint (SQL Server)
2 bytes-32.76832.767smallint
3 bytes-8.388.6088.388.607MEDIUMINT (só no MySQL)
4 bytes-2.147.483.6482.147.483.647integer / int
8 bytes-9.223.372.036.854.775.8089.223.372.036.854.775.807bigint; o INTEGER do SQLite

Pegadinhas entre bancos

  • REAL não é igual em todo lugar. No SQLite, tem 8 bytes. No PostgreSQL e no SQL Server, real tem 4 bytes (menos precisão). No MySQL, REAL é sinônimo de DOUBLE (a não ser com o modo REAL_AS_FLOAT).
  • O n do SQL Server conta bytes. A documentação da Microsoft avisa: em varchar(n), n é o tamanho em bytes, não em letras. Com acentos em UTF-8, cabem menos letras.
  • TIMESTAMP do MySQL acaba em 2038. Para datas fora de 1970–2038, use DATETIME.
  • Dinheiro: nos bancos rígidos, use o decimal exato (DECIMAL/numeric). No SQLite, guarde em REAL e arredonde, ou guarde os centavos num INTEGER.

A mesma tabela de clientes, em cada dialeto, só para comparar (ilustrativo: só a versão do SQLite roda aqui):

CREATE TABLE clientes (
    id         integer PRIMARY KEY,
    nome       varchar(100) NOT NULL,
    estado     char(2),
    nascimento date,
    vip        boolean NOT NULL DEFAULT false
);
CREATE TABLE clientes (
    id         INT PRIMARY KEY,
    nome       VARCHAR(100) NOT NULL,
    estado     CHAR(2),
    nascimento DATE,
    vip        BOOLEAN NOT NULL DEFAULT FALSE
);
CREATE TABLE clientes (
    id         int PRIMARY KEY,
    nome       nvarchar(100) NOT NULL,
    estado     char(2),
    nascimento date,
    vip        bit NOT NULL DEFAULT 0
);
CREATE TABLE clientes_novos (
    id         INTEGER PRIMARY KEY,
    nome       TEXT NOT NULL,
    estado     TEXT,
    nascimento TEXT,
    vip        INTEGER NOT NULL DEFAULT 0
) STRICT;

Erros comuns

SituaçãoMensagem (ou sintoma)O que fazer
Texto numa coluna INTEGER de tabela STRICTcannot store TEXT value in INTEGER column s.nMande um número, ou mude a coluna
Número com casas decimais numa coluna INT de tabela STRICTcannot store REAL value in INT column s.nArredonde antes ou use REAL
Nome de tipo de outro banco em tabela STRICTunknown datatype for s.d: "DATE"Use só INT, INTEGER, REAL, TEXT, BLOB ou ANY
Texto numa coluna INTEGER de tabela comumSem erro: o texto fica guardado como textoConfira com typeof(); proteja com STRICT ou CHECK
VARCHAR(2) recebendo um texto maiorSem erro: o SQLite ignora o 2Use CHECK (length(uf) = 2)
CAST('abc' AS INTEGER)Sem erro: dá 0Confira os dados antes de converter
0.1 + 0.2 = 0.3Dá 0 (falso)Compare valores arredondados
CREATE TABLE s (n INTEGER, t TEXT) STRICT;
INSERT INTO s VALUES ('abc', 'x');
CREATE TABLE s (n INTEGER, d DATE) STRICT;

Resumo

  • O SQLite guarda cada valor numa de cinco classes: NULL, INTEGER, REAL, TEXT e BLOB. typeof() mostra qual.
  • O nome de tipo da coluna vira uma afinidade (INTEGER, TEXT, BLOB, REAL ou NUMERIC), pelas cinco regras da documentação. Os números entre parênteses são ignorados.
  • Tabelas STRICT recusam o tipo errado e só aceitam INT, INTEGER, REAL, TEXT, BLOB e ANY.
  • Datas vão em TEXT ISO (ou dia juliano em REAL, ou tempo Unix em INTEGER); booleanos vão em INTEGER 0/1.
  • PostgreSQL, MySQL e SQL Server são rígidos e têm nomes e limites próprios; cuidado com REAL, com o n em bytes do SQL Server e com o TIMESTAMP do MySQL.