beginner20-30 minutosLição 7 de 10

Tipos de Dados e Restrições SQL

Aprofunde-se em tipos de dados SQL (INT, VARCHAR, TEXT, DATE, DECIMAL) e restrições (NOT NULL, UNIQUE, PRIMARY KEY, FOREIGN KEY, CHECK, DEFAULT)

Tipos de Dados e Restrições SQL

Escolher o tipo de dado correto e aplicar restrições apropriadas garante integridade dos dados, otimiza armazenamento e previne bugs em aplicações.

Tipos de Dados SQL

Tipos Numéricos

TipoArmazenamentoFaixa / PrecisãoCaso de Uso
INTEGER / INT4 bytes-2^31 a 2^31-1Contagens, IDs, idades
SMALLINT2 bytes-32.768 a 32.767Faixas pequenas, códigos de status
BIGINT8 bytes-2^63 a 2^63-1Contadores grandes, IDs grandes
DECIMAL(p,s)VariávelPrecisão exataDinheiro, medições científicas
REAL / FLOAT4-8 bytesAproximadoPercentagens, médias (não dinheiro!)
sql
CREATE TABLE products ( id INTEGER PRIMARY KEY, price DECIMAL(10,2) NOT NULL, -- 10 dígitos, 2 após o decimal rating DECIMAL(3,2), -- ex. 4.75 stock SMALLINT DEFAULT 0 );
⚠️Warning

Nunca use FLOAT ou REAL para valores monetários. Erros de arredondamento de ponto flutuante (ex.: 0.1 + 0.2 = 0.30000000000000004) causarão discrepâncias contábeis. Sempre use DECIMAL.

Tipos de Caractere/String

TipoDescriçãoCaso de Uso
CHAR(n)Comprimento fixo, preenchido com espaçosCódigos, CEPs, hashes
VARCHAR(n)Comprimento variável com máximoNomes, emails, endereços
TEXTComprimento ilimitadoArtigos, descrições, JSON
sql
CREATE TABLE articles ( title VARCHAR(200) NOT NULL, slug VARCHAR(200) NOT NULL, body TEXT, excerpt VARCHAR(500) );
ℹ️Note

VARCHAR(255) é um padrão comum porque 255 é o comprimento máximo que pode ser codificado com um prefixo de um byte. Use TEXT quando o conteúdo puder exceder algumas centenas de caracteres.

Tipos de Data/Hora

TipoFormatoExemploPrecisão
DATEYYYY-MM-DD2024-01-15Dia
TIMEHH:MM:SS14:30:00Segundo
TIMESTAMPYYYY-MM-DD HH:MM:SS2024-01-15 14:30:00Segundo (ou sub-segundo)
DATETIMEYYYY-MM-DD HH:MM:SS2024-01-15 14:30:00Sem fuso horário (MySQL)
sql
CREATE TABLE events ( event_name VARCHAR(200), event_date DATE, start_time TIME, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );

Outros Tipos Úteis

TipoCaso de Uso
BOOLEANFlags verdadeiro/falso
BLOBDados binários (imagens, arquivos)
JSONDados aninhados estruturados (PostgreSQL, MySQL)
UUIDIdentificadores universalmente únicos
ENUMLista fixa de valores (MySQL)

Restrições

Restrições impõem regras sobre os dados em suas tabelas.

NOT NULL

Garante que uma coluna não pode conter NULL:

sql
CREATE TABLE users ( email VARCHAR(255) NOT NULL, name VARCHAR(100) NOT NULL );
sql
-- Isto falhará INSERT INTO users (name) VALUES ('Alice'); -- email é NULL, viola NOT NULL

UNIQUE

Garante que todos os valores em uma coluna (ou combinação de colunas) são distintos:

sql
CREATE TABLE users ( email VARCHAR(255) NOT NULL UNIQUE, username VARCHAR(50) NOT NULL UNIQUE );
sql
-- Isto falhará INSERT INTO users (email, username) VALUES ('a@x.com', 'alice'); INSERT INTO users (email, username) VALUES ('b@x.com', 'alice'); -- username duplicado
Success

UNIQUE também cria um índice, tornando as buscas rápidas. Use-o para chaves naturais como email, nome de usuário ou SKU.

PRIMARY KEY

Identifica exclusivamente cada linha. Combina NOT NULL + UNIQUE. Uma tabela pode ter apenas uma:

sql
-- PK de coluna única CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, email VARCHAR(255) NOT NULL ); -- PK composta (múltiplas colunas) CREATE TABLE order_items ( order_id INTEGER, product_id INTEGER, quantity INTEGER, PRIMARY KEY (order_id, product_id) );

FOREIGN KEY

Vincula linhas entre tabelas e mantém a integridade referencial:

sql
CREATE TABLE orders ( id INTEGER PRIMARY KEY, user_id INTEGER NOT NULL, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE );

Ações Relacionais

AçãoOn DeleteOn Update
CASCADEExcluir linhas filhasAtualizar valores FK filhos
SET NULLDefinir FK filho como NULLDefinir FK filho como NULL
RESTRICTImpedir exclusão do paiImpedir atualização do pai
NO ACTIONMesmo que RESTRICT (verificável adiado)
SET DEFAULTDefinir para valor padrãoDefinir para valor padrão
sql
-- Se o usuário for excluído, seus pedidos também são excluídos FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE -- Se o usuário for excluído, os pedidos mantêm user_id como NULL FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
⚠️Warning

ON DELETE CASCADE é poderoso, mas perigoso. Excluir acidentalmente uma linha pai pode eliminar milhares de linhas filhas silenciosamente. Use com cautela.

CHECK

Valida que os valores atendem a uma condição:

sql
CREATE TABLE employees ( id INTEGER PRIMARY KEY, salary DECIMAL(10,2) CHECK (salary > 0), age INTEGER CHECK (age >= 16 AND age <= 120), department VARCHAR(50) CHECK (department IN ('Engineering', 'Sales', 'HR')) );
sql
-- Isto falhará INSERT INTO employees (salary, age, department) VALUES (-500, 150, 'Gaming'); -- salário negativo, idade excessiva, departamento inválido

DEFAULT

Define um valor quando nenhum é fornecido:

sql
CREATE TABLE orders ( id INTEGER PRIMARY KEY, status VARCHAR(20) DEFAULT 'pending', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, currency VARCHAR(3) DEFAULT 'USD' );
sql
INSERT INTO orders (id) VALUES (1); -- status = 'pending', created_at = agora, currency = 'USD'

Tudo Junto: Uma Tabela Bem Projetada

sql
CREATE TABLE accounts ( id INTEGER PRIMARY KEY AUTOINCREMENT, username VARCHAR(50) NOT NULL UNIQUE, email VARCHAR(255) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, role VARCHAR(20) NOT NULL DEFAULT 'user' CHECK (role IN ('user', 'admin', 'moderator')), is_active BOOLEAN NOT NULL DEFAULT TRUE, balance DECIMAL(12,2) NOT NULL DEFAULT 0.00 CHECK (balance >= 0), created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP );

Caso de Uso Real: Prevenindo Dados Ruins

sql
CREATE TABLE reviews ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, product_id INTEGER NOT NULL, rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5), title VARCHAR(200), body TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE CASCADE, UNIQUE (user_id, product_id) -- uma avaliação por usuário por produto );

Esta tabela garante:

  • A avaliação está sempre entre 1 e 5
  • Sem avaliações NULL
  • Uma avaliação por usuário por produto
  • Se um usuário/produto for excluído, as avaliações são limpas
  • A avaliação tem um timestamp de criação
Success

Restrições são sua primeira linha de defesa contra dados ruins. Defina-as no nível do banco de dados, não apenas no código da sua aplicação. As restrições do banco de dados se aplicam em todos os lugares — mesmo se alguém escrever um INSERT com bugs ou conectar-se de uma ferramenta diferente.

Perguntas de Prática

  1. Que tipo de dado você deve usar para uma coluna que armazena preços de produtos? Por quê?
  2. Escreva uma instrução CREATE TABLE para students com: id (PK), email (único, não nulo), age (verificar 0-150), enrollment_date (padrão hoje).
  3. Qual é a diferença entre CHAR(10) e VARCHAR(10)?
  4. O que ON DELETE CASCADE faz? Dê um exemplo onde é apropriado.
  5. Escreva uma restrição CHECK que garanta que uma coluna discount esteja entre 0 e 100 (inclusive).
  6. Uma tabela pode ter múltiplas restrições PRIMARY KEY? Pode ter múltiplas restrições UNIQUE?
  7. O que acontece com as linhas filhas quando uma linha pai é excluída com ON DELETE SET NULL?
  8. Escreva uma tabela enrollments com uma chave primária composta em (student_id, course_id) e chaves estrangeiras para ambas as tabelas.
  9. Por que você deve evitar FLOAT para colunas monetárias?
  10. Qual é a diferença de armazenamento entre INTEGER e SMALLINT? Quando você escolheria um sobre o outro?
Progresso70%