SQL DEFAULT

Quando a Loja Aurora cadastra um produto novo e ninguém diz quantos há no estoque, o estoque começa em 0. Quando entra um cliente novo, ele começa como não VIP. Ninguém precisa escrever isso em cada INSERT: o banco preenche sozinho. Quem faz isso é o DEFAULT ("padrão"), a restrição que dá a uma coluna um valor padrão, usado sempre que o INSERT deixa a coluna de fora. Nesta aula você vai criar valores padrão com números, textos e a data de hoje, e vai ver quando o padrão não entra, que é onde mora a confusão.

Você vai aprender
  • Como escrever DEFAULT valor no CREATE TABLE, e quando o banco usa esse valor.
  • Os tipos de valor padrão: número, texto, NULL, e as palavras CURRENT_DATE, CURRENT_TIME e CURRENT_TIMESTAMP.
  • Valores padrão calculados, com uma expressão entre parênteses.
  • O INSERT … DEFAULT VALUES, que cria uma linha só com os padrões.
  • A dupla NOT NULL DEFAULT, e o DEFAULT no ALTER TABLE.
  • Os erros reais: padrão sem parênteses, padrão que olha outra coluna, NULL que não vira padrão.

A ideia: o formulário já preenchido

Sabe aquele formulário em que o campo "País" já vem marcado com Brasil? Você pode trocar, mas, se não mexer, vai Brasil. E o campo "Quantidade" do carrinho de compras, que já vem com 1? É a mesma ideia: um valor que vale quando ninguém diz outro.

No formulárioNa tabela
"País" já vem com Brasilpais TEXT DEFAULT 'Brasil'
"Quantidade" já vem com 1quantidade INTEGER DEFAULT 1
A pessoa troca o valorO INSERT informa a coluna: vale o que ele mandou
A pessoa não mexeO INSERT deixa a coluna de fora: vale o DEFAULT

Sem DEFAULT, a coluna esquecida fica com NULL. Na verdade, é isso mesmo: toda coluna tem um padrão, e quando você não escreve nenhum, o padrão é NULL.


1. O primeiro DEFAULT

A tabela pedidos da Loja Aurora tem frete REAL NOT NULL DEFAULT 0. Um pedido novo, sem falar do frete:

INSERT INTO pedidos (cliente_id, funcionario_id, data)
VALUES (27, 3, '2026-10-18');

SELECT * FROM pedidos WHERE id = 91;

O pedido 91 entrou com frete 0.0 (o padrão 0, guardado como número com decimais porque a coluna é REAL) e entregue_em NULL (a coluna não tem DEFAULT, então o padrão dela é NULL). E o id 91 veio de onde? Da chave primária, que se numera sozinha: assunto da aula PRIMARY KEY.

Agora uma tabela nova, com vários padrões:

CREATE TABLE avaliacoes (
    id         INTEGER,
    produto_id INTEGER NOT NULL,
    nota       INTEGER NOT NULL DEFAULT 5,
    comentario TEXT    DEFAULT 'Sem comentário',
    aprovada   INTEGER NOT NULL DEFAULT 0
);

INSERT INTO avaliacoes (id, produto_id) VALUES (1, 3);

SELECT * FROM avaliacoes;
DEFAULT 5
Um número: se o INSERT não disser a nota, ela vale 5.
DEFAULT 'Sem comentário'
Um texto, entre aspas simples, como todo texto em SQL.
NOT NULL DEFAULT 0
As duas regras juntas: a coluna é obrigatória, mas nunca vai faltar, porque tem um padrão. É o par mais comum (aula NOT NULL).
(id, produto_id)
O INSERT só falou de duas colunas; as outras três receberam os seus padrões.

A forma geral é sempre a mesma: o DEFAULT vem depois do tipo, junto das outras restrições, e a ordem entre elas não importa (NOT NULL DEFAULT 0 e DEFAULT 0 NOT NULL dão no mesmo).

nome_da_coluna  TIPO  [NOT NULL]  DEFAULT valor

E quando o INSERT informa a coluna? Aí vale o que ele mandou, e o padrão é ignorado:

CREATE TABLE avaliacoes (
    id         INTEGER,
    produto_id INTEGER NOT NULL,
    nota       INTEGER NOT NULL DEFAULT 5,
    comentario TEXT    DEFAULT 'Sem comentário'
);

INSERT INTO avaliacoes (id, produto_id, nota, comentario)
VALUES (1, 3, 2, 'A ponta quebra fácil');

SELECT * FROM avaliacoes;

Experimente: toda entrega nova da loja começa com a situação pendente. Rode e veja: como o INSERT não fala da coluna situacao, ela ficou NULL. Dê à coluna o valor padrão 'pendente', sem mexer no INSERT.

CREATE TABLE entregas (
    id        INTEGER,
    pedido_id INTEGER NOT NULL,
    situacao  TEXT
);

INSERT INTO entregas (id, pedido_id) VALUES (1, 86);

SELECT * FROM entregas;
CREATE TABLE entregas (
    id        INTEGER,
    pedido_id INTEGER NOT NULL,
    situacao  TEXT DEFAULT 'pendente'
);

INSERT INTO entregas (id, pedido_id) VALUES (1, 86);

SELECT * FROM entregas;

2. A data de hoje: CURRENT_DATE

"Quando esta avaliação foi feita?" É o caso clássico de valor padrão: a data do momento em que a linha entrou. O SQLite tem três palavras especiais para isso:

PalavraFormatoExemplo
CURRENT_DATEAAAA-MM-DD2026-10-18
CURRENT_TIMEHH:MM:SS13:53:14
CURRENT_TIMESTAMPAAAA-MM-DD HH:MM:SS2026-10-18 13:53:14
CREATE TABLE avaliacoes (
    id         INTEGER,
    produto_id INTEGER NOT NULL,
    criada_em  TEXT NOT NULL DEFAULT CURRENT_DATE
);

INSERT INTO avaliacoes (id, produto_id) VALUES (1, 3);

SELECT * FROM avaliacoes;

O quadro mostra a data de hoje, o dia em que você está lendo esta página: o SQLite calculou na hora em que o INSERT rodou, no seu navegador. Rode amanhã e verá outra data.

O horário é o de Greenwich (UTC), não o do Brasil

A documentação do SQLite diz: esses valores são a data e a hora atuais em UTC (o "horário universal", o de Londres no inverno). O Brasil (o horário de Brasília) está 3 horas atrás. A Ana viu isso no terminal: a avaliação gravou 13:53, mas no relógio do notebook dela eram 10:53. Para mostrar no horário local, converta na consulta com datetime(…, 'localtime'):

$ sqlite3 loja.db
SQLite version 3.50.4 2025-07-30 19:33:53
Enter ".help" for usage hints.
sqlite> CREATE TABLE avaliacoes (id INTEGER, produto_id INTEGER, criada_em TEXT DEFAULT CURRENT_TIMESTAMP);
sqlite> INSERT INTO avaliacoes (id, produto_id) VALUES (1, 3);
sqlite> SELECT * FROM avaliacoes;
1|3|2026-10-18 13:53:14           « guardado em UTC
sqlite> SELECT datetime(criada_em, 'localtime') FROM avaliacoes;
2026-10-18 10:53:14               « o mesmo instante, no fuso do notebook
sqlite> .quit

Perto da meia-noite isso pesa até no CURRENT_DATE: às 22h no Brasil, em UTC já é o dia seguinte. Guardar em UTC é uma boa prática (todos os registros ficam na mesma régua); só lembre de converter na hora de mostrar. Mais em Datas e Horas.


3. Padrões calculados: a expressão entre parênteses

E se o padrão precisa de uma conta? Um cupom de desconto, por exemplo, que vale por 30 dias a partir de hoje. A função date('now', '+30 days') (aula Funções de Data) calcula essa data. Para usar uma expressão como padrão, ela vai entre parênteses:

CREATE TABLE cupons (
    codigo   TEXT NOT NULL,
    desconto REAL NOT NULL DEFAULT 10,
    validade TEXT NOT NULL DEFAULT (date('now', '+30 days'))
);

INSERT INTO cupons (codigo) VALUES ('AURORA10');

SELECT codigo, desconto, validade > date('now') AS ainda_vale FROM cupons;
DEFAULT ( … )
Os parênteses dizem "isto é uma expressão: calcule". O SQLite calcula uma vez para cada linha inserida.
date('now', '+30 days')
A data de hoje mais 30 dias, no formato AAAA-MM-DD.
validade > date('now')
Só para conferir: a validade é depois de hoje, então dá 1 ("verdadeiro"). (Mostrar a data em si daria um valor diferente a cada dia.)

Sem os parênteses, o SQLite não entende (veja em Quando dá errado). Os valores "simples" (um número, um texto entre aspas, NULL, TRUE, CURRENT_DATE…) não precisam de parênteses.

O padrão não pode olhar outras colunas

A Ana tentou um preço promocional que fosse, por padrão, 90% do preço normal:

CREATE TABLE ofertas (
    produto_id  INTEGER NOT NULL,
    preco       REAL NOT NULL,
    preco_promo REAL DEFAULT (preco * 0.9)
);

"O valor padrão da coluna preco_promo não é constante." A expressão de um DEFAULT pode usar funções e contas, mas não pode citar colunas (nem a da própria linha), nem fazer consultas a outras tabelas. O padrão é decidido antes de a linha existir. Para "90% do preço", calcule no INSERT ou na consulta (SELECT preco * 0.9 …).


4. DEFAULT VALUES: uma linha só de padrões

Se todas as colunas têm um padrão que serve, existe um atalho: INSERT INTO tabela DEFAULT VALUES, sem lista de colunas e sem VALUES (…).

CREATE TABLE contadores (
    visitas  INTEGER NOT NULL DEFAULT 0,
    situacao TEXT    NOT NULL DEFAULT 'aberto'
);

INSERT INTO contadores DEFAULT VALUES;
INSERT INTO contadores DEFAULT VALUES;

SELECT * FROM contadores;

Duas linhas iguais, só com os padrões. Uma coluna sem DEFAULT receberia NULL (e, se fosse NOT NULL, o comando daria erro). Na prática, é um comando raro; ele aparece mais em tabelas cujo id se numera sozinho.


5. DEFAULT numa tabela que já existe

A Loja Aurora vai começar a marcar os produtos em promoção. A coluna nova entra com ALTER TABLE (aula ALTER TABLE), e o DEFAULT preenche os 45 produtos que já existem:

ALTER TABLE produtos ADD COLUMN em_promocao INTEGER NOT NULL DEFAULT 0;

SELECT id, nome, em_promocao FROM produtos LIMIT 3;

Todos ganharam 0. Sem o DEFAULT, essa coluna NOT NULL não poderia nem ser criada (o erro está na aula NOT NULL). Mas há um limite: no ALTER TABLE, o SQLite só aceita padrões constantes. A data de hoje não serve:

ALTER TABLE produtos ADD COLUMN cadastrado_em TEXT DEFAULT CURRENT_TIMESTAMP;

"Não é possível acrescentar uma coluna com padrão não constante." A saída é acrescentar a coluna com um padrão fixo (ou sem padrão) e preencher depois com um UPDATE.


Formas diferentes de usar o padrão

FormaExemploQuando usar
Deixar a coluna fora do INSERTINSERT INTO avaliacoes (id, produto_id) VALUES (1, 3);O jeito normal: o padrão entra sozinho
DEFAULT VALUESINSERT INTO contadores DEFAULT VALUES;Todas as colunas com o padrão
Escrever o valorINSERT INTO avaliacoes (id, produto_id, nota) VALUES (1, 3, 5);Quando você quer deixar claro o valor, mesmo que seja igual ao padrão
DEFAULT dentro do VALUESVALUES (1, 3, DEFAULT)Não funciona no SQLite (dá erro de sintaxe); funciona no PostgreSQL, no MySQL e no SQL Server
Valor padrãoExemploPrecisa de parênteses?
NúmeroDEFAULT 0, DEFAULT -1, DEFAULT 4.5Não
TextoDEFAULT 'pendente'Não
Verdadeiro/falsoDEFAULT TRUE (vira 1)Não
NULLDEFAULT NULL (o mesmo que não escrever)Não
Data e hora atuais (UTC)DEFAULT CURRENT_DATE, DEFAULT CURRENT_TIMESTAMPNão
ExpressãoDEFAULT (date('now', '+30 days'))Sim

Para ver o padrão de cada coluna, o PRAGMA table_info mostra na coluna dflt_value (de default value), exatamente como foi escrito:

SELECT name, "notnull", dflt_value FROM pragma_table_info('produtos');

Quando dá errado

Mandou NULL esperando o padrão

O padrão só entra quando a coluna fica de fora. Um NULL escrito no INSERT é um valor como outro qualquer, e ele ganha do padrão:

CREATE TABLE avaliacoes (
    id         INTEGER,
    produto_id INTEGER NOT NULL,
    comentario TEXT DEFAULT 'Sem comentário'
);

INSERT INTO avaliacoes (id, produto_id, comentario) VALUES (1, 3, NULL);

SELECT * FROM avaliacoes;

O comentário ficou NULL, não "Sem comentário". Se a coluna for NOT NULL, é pior: erro. Na tabela pedidos, o frete é NOT NULL DEFAULT 0:

INSERT INTO pedidos (cliente_id, funcionario_id, data, frete)
VALUES (27, 3, '2026-10-18', NULL);

Como consertar: para usar o padrão, tire a coluna da lista do INSERT. Isso costuma acontecer em programas que montam o INSERT sempre com todas as colunas e mandam NULL nas que o usuário não preencheu.

INSERT sem lista de colunas
CREATE TABLE entregas (id INTEGER, situacao TEXT DEFAULT 'pendente');

INSERT INTO entregas VALUES (1);

O que diz: table entregas has 2 columns but 1 values were supplied. Sem a lista de colunas, o INSERT precisa de um valor para cada coluna, e o padrão não "completa" o que faltou. Como consertar: INSERT INTO entregas (id) VALUES (1);. Escrever a lista de colunas é sempre uma boa prática.

Uma função como padrão, sem parênteses
CREATE TABLE cupons (
    codigo   TEXT NOT NULL,
    validade TEXT DEFAULT date('now', '+30 days')
);

O que diz: near "(": syntax error. Depois do DEFAULT, o SQLite esperava um valor simples, leu date e tropeçou no parêntese. Como consertar: ponha a expressão inteira entre parênteses: DEFAULT (date('now', '+30 days')).

A palavra DEFAULT dentro do VALUES
CREATE TABLE entregas (id INTEGER, situacao TEXT DEFAULT 'pendente');

INSERT INTO entregas (id, situacao) VALUES (1, DEFAULT);

O que diz: near "DEFAULT": syntax error. Quem vem do PostgreSQL ou do MySQL estranha, porque lá isso funciona. Como consertar: no SQLite, tire a coluna da lista: INSERT INTO entregas (id) VALUES (1);.

Um padrão que não combina com o tipo
CREATE TABLE notas (id INTEGER, nota INTEGER DEFAULT 'cinco');

INSERT INTO notas (id) VALUES (1);

SELECT nota, typeof(nota) FROM notas;

O que acontece: o CREATE TABLE não confere se o padrão combina com o tipo, e a tabela normal guarda o texto 'cinco' numa coluna INTEGER (aula Os Tipos no SQLite). Numa tabela STRICT, o erro aparece no primeiro INSERT: cannot store TEXT value in INTEGER column notas.nota. Como evitar: confira que o padrão é do mesmo tipo da coluna.

Nos outros bancos

DEFAULT é do SQL padrão e se escreve igual no MySQL, no PostgreSQL e no SQL Server: frete DECIMAL(10,2) NOT NULL DEFAULT 0. Duas diferenças úteis:

  • Os três aceitam a palavra DEFAULT no lugar de um valor, dentro do VALUES, para pedir o padrão de uma coluna (trecho ilustrativo, não roda no SQLite):
INSERT INTO entregas (id, situacao) VALUES (1, DEFAULT);
  • INSERT INTO tabela DEFAULT VALUES existe também no PostgreSQL e no SQL Server. No MySQL, a forma documentada é INSERT INTO tabela () VALUES ();.

Referência rápida

EscritaO que faz
coluna TIPO DEFAULT valorValor usado quando o INSERT deixa a coluna de fora
coluna TIPO NOT NULL DEFAULT valorObrigatória, com padrão
DEFAULT CURRENT_DATE / CURRENT_TIME / CURRENT_TIMESTAMPData, hora ou data e hora do momento do INSERT, em UTC
DEFAULT (expressão)Padrão calculado a cada linha; sem citar colunas
INSERT INTO t DEFAULT VALUES;Uma linha só com os padrões
SELECT name, dflt_value FROM pragma_table_info('t');Mostra o padrão de cada coluna
Mensagem do SQLiteQuer dizer
near "(": syntax errorUma expressão no DEFAULT sem parênteses
default value of column [x] is not constantO padrão cita uma coluna (ou faz uma consulta)
Cannot add a column with non-constant defaultALTER TABLE … ADD COLUMN com CURRENT_TIMESTAMP ou expressão
near "DEFAULT": syntax errorDEFAULT dentro do VALUES, que o SQLite não aceita
NOT NULL constraint failed: t.cMandou NULL numa coluna NOT NULL, mesmo que ela tenha padrão

Exercícios

1. País padrão

Complete para que o país dos fornecedores novos seja Brasil quando ninguém informar:

pais TEXT NOT NULL

2. A data de hoje

Complete com a palavra que dá a data de hoje (sem a hora):

criada_em TEXT DEFAULT

3. A coluna é comentario TEXT DEFAULT 'Sem comentário'. O INSERT manda NULL nela. O que fica guardado?

4. Qual destes DEFAULT dá erro no SQLite?

5. Em que fuso horário o CURRENT_TIMESTAMP do SQLite grava a hora?

6. Por que preco_promo REAL DEFAULT (preco * 0.9) dá erro?

Missão final: avaliações com padrões

Missão: toda avaliação nova começa não aprovada (a coluna aprovada vale 0) e guarda a data em que foi feita (a coluna criada_em, com a data de hoje). As duas colunas são obrigatórias. Complete o CREATE TABLE com NOT NULL e o DEFAULT certo em cada uma; os INSERT não falam delas, e têm de continuar funcionando.

CREATE TABLE avaliacoes (
    id         INTEGER,
    produto_id INTEGER NOT NULL,
    nota       INTEGER NOT NULL,
    aprovada   INTEGER,
    criada_em  TEXT
);

INSERT INTO avaliacoes (id, produto_id, nota) VALUES (1, 3, 5);
INSERT INTO avaliacoes (id, produto_id, nota) VALUES (2, 10, 4);

PRAGMA table_info(avaliacoes);
CREATE TABLE avaliacoes (
    id         INTEGER,
    produto_id INTEGER NOT NULL,
    nota       INTEGER NOT NULL,
    aprovada   INTEGER NOT NULL DEFAULT 0,
    criada_em  TEXT NOT NULL DEFAULT CURRENT_DATE
);

INSERT INTO avaliacoes (id, produto_id, nota) VALUES (1, 3, 5);
INSERT INTO avaliacoes (id, produto_id, nota) VALUES (2, 10, 4);

PRAGMA table_info(avaliacoes);

Depois de cumprir, troque o PRAGMA por SELECT * FROM avaliacoes; para ver as duas avaliações com o 0 e a data de hoje.


Resumo

  • DEFAULT valor dá à coluna um valor padrão, usado quando o INSERT a deixa de fora. Sem DEFAULT, o padrão é NULL.
  • O padrão pode ser um número, um texto entre aspas simples, NULL, TRUE/FALSE, CURRENT_DATE, CURRENT_TIME ou CURRENT_TIMESTAMP (em UTC), ou uma expressão entre parênteses que não cite colunas.
  • NULL escrito no INSERT não aciona o padrão: fica NULL (ou dá erro, se a coluna for NOT NULL).
  • INSERT INTO t DEFAULT VALUES; cria uma linha só com padrões. O SQLite não aceita DEFAULT dentro do VALUES.
  • No ALTER TABLE … ADD COLUMN, o padrão preenche as linhas antigas, mas tem de ser constante.