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.
- 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):
| Classe | O que guarda | Como se escreve | typeof() devolve | Tamanho (documentação do SQLite) |
|---|---|---|---|---|
NULL | "Sem valor" | NULL | null | — |
INTEGER | Número inteiro com sinal | 42, -7, 0 | integer | 0, 1, 2, 3, 4, 6 ou 8 bytes, conforme o tamanho do número |
REAL | Número com casas decimais (aproximado) | 4.9, 1.0, 1e3 | real | Sempre 8 bytes (ponto flutuante IEEE) |
TEXT | Texto | 'Teresina' (aspas simples) | text | O tamanho do texto, na codificação do banco (UTF-8 na Loja Aurora) |
BLOB | Bytes guardados exatamente como chegaram (uma imagem, um arquivo) | x'CAFE' (bytes em hexadecimal) | blob | O 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:
| Regra | Se o nome do tipo… | Afinidade | Exemplos da documentação |
|---|---|---|---|
| 1 | contém INT | INTEGER | INT, INTEGER, TINYINT, SMALLINT, MEDIUMINT, BIGINT, UNSIGNED BIG INT, INT2, INT8 |
| 2 | contém CHAR, CLOB ou TEXT | TEXT | CHARACTER(20), VARCHAR(255), VARYING CHARACTER(255), NCHAR(55), NATIVE CHARACTER(70), NVARCHAR(100), TEXT, CLOB |
| 3 | contém BLOB, ou não tem tipo | BLOB (nenhuma conversão) | BLOB, coluna sem tipo |
| 4 | contém REAL, FLOA ou DOUB | REAL | REAL, DOUBLE, DOUBLE PRECISION, FLOAT |
| 5 | nenhuma das anteriores | NUMERIC | NUMERIC, 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,DATETIMEeBOOLEANnão criam nada especial: caem na regra 5, afinidade NUMERIC.- A ordem das regras importa:
FLOATING POINTtemINTno meio ("poINT") e vira INTEGER pela regra 1.
O que cada afinidade faz com o valor que chega
| Afinidade | Chega um texto que parece número ('19.90') | Chega um número | Chega um texto qualquer ('sim') |
|---|---|---|---|
| TEXT | Fica texto | Vira texto | Fica texto |
| NUMERIC | Vira número: inteiro se der, senão real | Fica número (3.0 vira o inteiro 3) | Fica texto |
| INTEGER | Igual à NUMERIC | Igual à NUMERIC | Fica texto |
| REAL | Vira real | Vira real (42 vira 42.0) | Fica texto |
| BLOB | Fica como chegou | Fica como chegou | Fica 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:
| Tipo | Aceita |
|---|---|
INT ou INTEGER | Inteiros, e o que vira inteiro sem perder nada ('5', 3.0) |
REAL | Números; um inteiro vira real |
TEXT | Texto; um número vira texto |
BLOB | Só bytes |
ANY | Qualquer 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:
| Dado | Classe usada | Formato | Exemplo |
|---|---|---|---|
| Data e hora | TEXT | ISO 8601: 'AAAA-MM-DD HH:MM:SS.SSS' | '2026-10-14', '2026-10-14 15:30:00' |
| Data e hora | REAL | Dia juliano: dias desde o meio-dia de 24/11/4714 a.C. (em Greenwich) | 2461327.5 |
| Data e hora | INTEGER | Tempo Unix: segundos desde 1970-01-01 00:00:00 UTC | 1791936000 |
| Booleano | INTEGER | 1 = verdadeiro, 0 = falso; TRUE e FALSE (desde a versão 3.23.0) são só outros nomes para 1 e 0 | vip = 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
| Escrita | O que faz | Exemplo | Resultado |
|---|---|---|---|
typeof(x) | A classe do valor: null, integer, real, text ou blob | SELECT typeof(preco) FROM produtos WHERE id = 1; | real |
CAST(x AS INTEGER) | Converte para inteiro; corta as casas decimais | SELECT CAST(3.99 AS INTEGER); | 3 |
| De texto: lê os algarismos do começo | SELECT CAST('12abc' AS INTEGER); | 12 | |
| Texto sem número nenhum vira 0, sem erro | SELECT CAST('abc' AS INTEGER); | 0 | |
CAST(x AS REAL) | Converte para real | SELECT CAST('4.9' AS REAL); | 4.9 |
CAST(x AS TEXT) | Converte para texto | SELECT 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;
| Tipo | Colunas da Loja Aurora | Por quê |
|---|---|---|
INTEGER | id, os …_id, estoque, quantidade, vip, descontinuado | Contagens, números de ficha e sim/não (0 ou 1) |
REAL | preco, preco_unitario, frete, salario | Valores com centavos (arredonde com round() nas contas) |
TEXT | nomes, email, cidade, estado, telefone, data, nascimento, entregue_em | Textos 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
| Caso | Exemplo | Resultado | O que acontece |
|---|---|---|---|
| Maior inteiro (8 bytes) | SELECT 9223372036854775807; | 9223372036854775807 | 263 − 1 |
| Passou do limite | SELECT 9223372036854775807 + 1; | 9.22337203685478e+18 | A conta vira real (aproximado), sem erro |
| Divisão de inteiros | SELECT 7 / 2; | 3 | Inteiro dividido por inteiro dá inteiro |
| Com um real na conta | SELECT 7 / 2.0; | 3.5 | Basta um dos lados ser real |
| Decimais aproximados | SELECT 0.1 + 0.2 = 0.3; | 0 | O real guarda um valor muito próximo, não exato |
| Arredondando | SELECT round(0.1 + 0.2, 2); | 0.3 | Arredonde 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.
| Dado | SQLite | PostgreSQL | MySQL | SQL Server |
|---|---|---|---|---|
| Inteiro pequeno | INTEGER | smallint (2 bytes) | TINYINT (1 byte), SMALLINT (2 bytes) | tinyint (1 byte, só 0 a 255), smallint (2 bytes) |
| Inteiro | INTEGER | integer ou int (4 bytes) | INT (4 bytes) | int (4 bytes) |
| Inteiro grande | INTEGER (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írgula | decimal(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 duplo | REAL (8 bytes) | double precision (8 bytes, 15 algarismos) | DOUBLE (precisão dupla, cerca de 15 casas) | float (8 bytes, 15 algarismos) |
| Texto de tamanho fixo | TEXT | char(n) | CHAR(M), M de 0 a 255 letras | char(n), n de 1 a 8.000 bytes |
| Texto com limite | TEXT (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 longo | TEXT | text | TEXT (65.535 bytes), MEDIUMTEXT, LONGTEXT (4 GB) | varchar(max) ou nvarchar(max) (2 GB) |
| Data | TEXT 'AAAA-MM-DD' | date | DATE, de 1000-01-01 a 9999-12-31 | date, de 0001-01-01 a 9999-12-31 |
| Data e hora | TEXT 'AAAA-MM-DD HH:MM:SS' | timestamp; com fuso: timestamptz | DATETIME (1000 a 9999); TIMESTAMP (1970 a 2038, em UTC) | datetime2, de 0001 a 9999 |
| Verdadeiro/falso | INTEGER 0/1 | boolean | BOOLEAN = TINYINT(1) | bit (1, 0 ou NULL) |
| Binário | BLOB | bytea | BLOB (65.535 bytes) | varbinary(n), n até 8.000; varbinary(max) |
As faixas dos inteiros
| Tamanho | Menor valor | Maior valor | Nomes |
|---|---|---|---|
| 1 byte | -128 (MySQL) ou 0 (SQL Server) | 127 (MySQL) ou 255 (SQL Server) | TINYINT (MySQL), tinyint (SQL Server) |
| 2 bytes | -32.768 | 32.767 | smallint |
| 3 bytes | -8.388.608 | 8.388.607 | MEDIUMINT (só no MySQL) |
| 4 bytes | -2.147.483.648 | 2.147.483.647 | integer / int |
| 8 bytes | -9.223.372.036.854.775.808 | 9.223.372.036.854.775.807 | bigint; o INTEGER do SQLite |
Pegadinhas entre bancos
REALnão é igual em todo lugar. No SQLite, tem 8 bytes. No PostgreSQL e no SQL Server,realtem 4 bytes (menos precisão). No MySQL,REALé sinônimo deDOUBLE(a não ser com o modoREAL_AS_FLOAT).- O
ndo SQL Server conta bytes. A documentação da Microsoft avisa: emvarchar(n),né o tamanho em bytes, não em letras. Com acentos em UTF-8, cabem menos letras. TIMESTAMPdo MySQL acaba em 2038. Para datas fora de 1970–2038, useDATETIME.- Dinheiro: nos bancos rígidos, use o decimal exato (
DECIMAL/numeric). No SQLite, guarde emREALe arredonde, ou guarde os centavos numINTEGER.
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ção | Mensagem (ou sintoma) | O que fazer |
|---|---|---|
Texto numa coluna INTEGER de tabela STRICT | cannot store TEXT value in INTEGER column s.n | Mande um número, ou mude a coluna |
Número com casas decimais numa coluna INT de tabela STRICT | cannot store REAL value in INT column s.n | Arredonde antes ou use REAL |
Nome de tipo de outro banco em tabela STRICT | unknown datatype for s.d: "DATE" | Use só INT, INTEGER, REAL, TEXT, BLOB ou ANY |
Texto numa coluna INTEGER de tabela comum | Sem erro: o texto fica guardado como texto | Confira com typeof(); proteja com STRICT ou CHECK |
VARCHAR(2) recebendo um texto maior | Sem erro: o SQLite ignora o 2 | Use CHECK (length(uf) = 2) |
CAST('abc' AS INTEGER) | Sem erro: dá 0 | Confira os dados antes de converter |
0.1 + 0.2 = 0.3 | Dá 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,TEXTeBLOB.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
STRICTrecusam o tipo errado e só aceitamINT,INTEGER,REAL,TEXT,BLOBeANY. - Datas vão em
TEXTISO (ou dia juliano emREAL, ou tempo Unix emINTEGER); booleanos vão emINTEGER0/1. - PostgreSQL, MySQL e SQL Server são rígidos e têm nomes e limites próprios; cuidado com
REAL, com onem bytes do SQL Server e com oTIMESTAMPdo MySQL.