Modificação do Banco de Dados

Autor

Douglas Braga

Além de consultar dados com SELECT, o SQL permite modificar o conteúdo de um banco de dados por meio de três comandos DML: INSERT (inserir), DELETE (excluir) e UPDATE (atualizar).

INSERT: Inserindo Dados

Inserção de uma única linha

A forma mais simples insere uma linha com valores explícitos:

-- Inserir um novo centro na UnDF
INSERT INTO centro (id_centro, sigla, nome_centro)
VALUES (4, 'COLAB', 'Centro de Laboratórios Avançados');

Ao inserir uma escola vinculada ao novo centro:

INSERT INTO escola (id_escola, sigla, nome_escola, id_centro)
VALUES (41, 'ELAB', 'Escola de Laboratórios', 4);

INSERT com SELECT

É possível inserir dados copiados de outra tabela com base em uma consulta. Suponha a existência de uma tabela disciplina_historico com a mesma estrutura de disciplina:

-- Criar tabela histórica (estrutura idêntica a disciplina)
CREATE TABLE disciplina_historico (
    id_disciplina   INTEGER      PRIMARY KEY,
    nome_disciplina VARCHAR(100) NOT NULL,
    id_curso        INTEGER,
    semestre        INTEGER,
    carga_horaria   INTEGER
);

-- Copiar para o histórico as disciplinas com carga horária acima de 150 h
INSERT INTO disciplina_historico
SELECT *
FROM   disciplina
WHERE  carga_horaria > 150;

Verificando o que seria inserido:

-- Disciplinas que seriam copiadas para o histórico (carga > 150 h)
SELECT id_disciplina, nome_disciplina, id_curso, carga_horaria
FROM   disciplina
WHERE  carga_horaria > 150
ORDER BY carga_horaria DESC;
2 records
id_disciplina nome_disciplina id_curso carga_horaria
3110401 Bases da Eng. de Software 4 311 180
3110802 Projeto Aplicado 8 - Sistema em Tempo Real 311 160

DELETE: Excluindo Dados

DELETE simples

-- Remover disciplinas de semestres ímpares (não fazem parte da nossa amostra)
DELETE FROM disciplina
WHERE  semestre % 2 = 1;

DELETE com subconsulta

Para condições mais complexas, o WHERE pode conter subconsultas:

-- Remover matrículas de alunos com nota abaixo de 5.0 em todas as disciplinas
DELETE FROM matricula_disciplina
WHERE  id_aluno IN (
    SELECT id_aluno
    FROM   matricula_disciplina
    GROUP BY id_aluno
    HAVING AVG(nota) < 5.0
);

Verificando quais alunos seriam afetados:

-- Alunos com média abaixo de 5.0
SELECT id_aluno, ROUND(AVG(nota), 2) AS media
FROM   matricula_disciplina
GROUP BY id_aluno
HAVING AVG(nota) < 5.0;
2 records
id_aluno media
2024311002 4.9
2025311002 4.0
Aviso

DELETE sem WHERE remove todas as linhas da tabela. Sempre verifique com um SELECT primeiro quais linhas serão afetadas antes de executar o DELETE.

UPDATE: Atualizando Dados

UPDATE simples

-- Renomear um curso (corrigir nome)
UPDATE curso
SET    nome_curso = 'Engenharia de Software (Bacharelado)'
WHERE  id_curso = 311;

UPDATE condicional

-- Aumentar carga horária das disciplinas de semestre 8 em 10%
UPDATE disciplina
SET    carga_horaria = ROUND(carga_horaria * 1.10)
WHERE  semestre = 8;

Verificando o que seria alterado:

-- Disciplinas de semestre 8 e como ficariam com +10% de carga horária
SELECT id_disciplina, nome_disciplina,
       carga_horaria                          AS carga_atual,
       ROUND(carga_horaria * 1.10)            AS carga_nova
FROM   disciplina
WHERE  semestre = 8
ORDER BY id_curso;
6 records
id_disciplina nome_disciplina carga_atual carga_nova
1110801 Monografia 100 110
1110802 Desenvolvimento Econômico 90 99
2110801 Tecnologia Educacional - Design 60 66
2110802 Estatística Aplicada 50 55
3110801 Bases da Eng. de Software 8 100 110
3110802 Projeto Aplicado 8 - Sistema em Tempo Real 160 176

UPDATE com CASE: reajuste diferenciado

Quando diferentes grupos de linhas precisam de atualizações diferentes, o CASE permite aplicar regras distintas em um único comando:

-- Ajuste de carga horária por faixa:
--   Disciplinas com carga <= 60 h → aumentar 20%
--   Disciplinas com carga > 60 h  → aumentar 10%
UPDATE disciplina
SET    carga_horaria = CASE
                          WHEN carga_horaria <= 60 THEN ROUND(carga_horaria * 1.20)
                          ELSE                          ROUND(carga_horaria * 1.10)
                       END;

Verificando o efeito por faixa:

-- Simular o ajuste sem alterar o banco
SELECT id_disciplina, id_curso, carga_horaria AS atual,
       CASE
           WHEN carga_horaria <= 60 THEN ROUND(carga_horaria * 1.20)
           ELSE                          ROUND(carga_horaria * 1.10)
       END AS proposto
FROM   disciplina
ORDER BY id_curso, semestre;
Displaying records 1 - 10
id_disciplina id_curso atual proposto
1110201 111 75 83
1110202 111 60 72
1110401 111 75 83
1110402 111 95 105
1110601 111 75 83
1110602 111 75 83
1110801 111 100 110
1110802 111 90 99
2110201 211 60 72
2110202 211 60 72

Vantagem do CASE em UPDATE:

O uso de um único UPDATE com CASE garante que o ajuste seja calculado com base nos valores originais — não há risco de uma linha receber o primeiro ajuste e depois entrar na faixa errada do segundo. Isso é diferente de usar dois UPDATEs separados.

UPDATE com subconsulta

-- Marcar como aprovadas todas as matrículas com nota >= 6.0
UPDATE matricula_disciplina
SET    aprovado = 1
WHERE  nota >= 6.0
  AND  aprovado IS NULL;

Verificando o estado atual:

-- Distribuição de aprovados e reprovados
SELECT aprovado,
       COUNT(*)           AS n_registros,
       ROUND(AVG(nota), 2) AS nota_media
FROM   matricula_disciplina
GROUP BY aprovado
ORDER BY aprovado;
2 records
aprovado n_registros nota_media
0 7 2.24
1 51 7.47

Resumo dos Comandos de Modificação

Comando Ação Cuidado
INSERT INTO ... VALUES Insere linhas com valores explícitos Respeitar restrições (PK, FK, NOT NULL, CHECK)
INSERT INTO ... SELECT Insere linhas copiadas de uma consulta A consulta deve retornar colunas compatíveis
DELETE FROM ... WHERE Remove linhas que satisfazem a condição Sem WHERE, remove todas as linhas
UPDATE ... SET ... WHERE Atualiza colunas das linhas que satisfazem a condição Sem WHERE, atualiza todas as linhas

Para Praticar

-- Simular: quais professores seriam afetados por um reajuste de 15%
-- para quem tem salário abaixo da média?
SELECT nome, id_escola, salario AS atual,
       ROUND(salario * 1.15, 2) AS apos_reajuste
FROM   professor
WHERE  salario < (SELECT AVG(salario) FROM professor)
ORDER BY salario;
3 records
nome id_escola atual apos_reajuste
Igor Melo 31 3100 3565
Eduarda Souza 21 3200 3680
Gustavo Costa 31 3300 3795
-- Simular: disciplinas que seriam removidas se excluíssemos as sem pré-requisitos
-- e sem matrícula (seguras para remover)
SELECT d.id_disciplina, d.nome_disciplina, d.id_curso
FROM   disciplina d
WHERE  d.id_disciplina NOT IN (SELECT id_disciplina FROM prereq)
  AND  d.id_disciplina NOT IN (SELECT id_prereq     FROM prereq)
  AND  d.id_disciplina NOT IN (SELECT DISTINCT id_disciplina FROM matricula_disciplina)
ORDER BY d.id_curso, d.id_disciplina;
2 records
id_disciplina nome_disciplina id_curso
1110802 Desenvolvimento Econômico 111
2110802 Estatística Aplicada 211
-- Violação de FK: tentar deletar uma disciplina que tem pré-requisitos
-- Isso geraria erro:
DELETE FROM disciplina WHERE id_disciplina = 3110201;
-- ERROR: update or delete on table "disciplina" violates foreign key constraint
-- "prereq_id_prereq_fkey" on table "prereq"
-- DETAIL: Key (id_disciplina)=(3110201) is still referenced from table "prereq".

-- Solução: deletar os pré-requisitos primeiro, ou usar CASCADE
DELETE FROM prereq     WHERE id_disciplina = 3110201 OR id_prereq = 3110201;
DELETE FROM disciplina WHERE id_disciplina = 3110201;
-- (não executar — apenas ilustrativo)
Aviso

Ordem importa no DELETE com FKs. Ao remover dados em tabelas com chaves estrangeiras, é preciso excluir primeiro as linhas das tabelas referenciantes antes das referenciadas. Alternativamente, defina a FK com ON DELETE CASCADE para que o banco faça isso automaticamente — mas use com cautela em produção.