Visões

Autor

Douglas Braga

Em muitas situações, não é desejável que todos os usuários vejam o modelo lógico completo do banco de dados. Uma visão (view) é uma relação virtual — não armazenada fisicamente — que expõe apenas os dados relevantes para cada perfil de usuário.

Uma visão é qualquer relação que não faz parte do modelo conceitual mas que é tornada visível ao usuário como uma relação virtual. Ela é definida por uma expressão de consulta e não ocupa espaço de armazenamento próprio.

Definindo uma Visão

A sintaxe de criação é:

CREATE VIEW <nome> AS <expressão de consulta>;

A definição da visão é salva pelo SGBD; a expressão de consulta é executada toda vez que a visão é referenciada em uma consulta.

Visão pública de professores — oculta o salário:

CREATE OR REPLACE VIEW professores_publico AS
SELECT id_prof, nome, id_escola, ch_semanal
FROM   professor;

Visão de carga salarial por escola:

CREATE OR REPLACE VIEW salario_escola(id_escola, total_salario, n_professores) AS
SELECT id_escola, SUM(salario), COUNT(*)
FROM   professor
GROUP BY id_escola;

Usando Visões

Uma vez definida, a visão pode ser usada em consultas exatamente como uma tabela real:

-- Consulta a visão pública (sem salário)
SELECT nome, ch_semanal
FROM   professores_publico
WHERE  id_escola = 31
ORDER BY nome;
3 records
nome ch_semanal
Gustavo Costa 20
Helena Carvalho 40
Igor Melo 20
-- Junta a visão de salário com a tabela escola
SELECT e.nome_escola, s.total_salario, s.n_professores,
       ROUND(s.total_salario::numeric / s.n_professores, 2) AS media_salario
FROM   salario_escola s
JOIN   escola e USING (id_escola)
ORDER BY s.total_salario DESC;
3 records
nome_escola total_salario n_professores media_salario
Escola Superior de Gestão 13100 2 6550.00
Escola Superior de Engenharias, Tecnologia e Inovação 13100 3 4366.67
Escola de Educação, Magistério e Arte 9600 2 4800.00

Visões Definidas sobre Outras Visões

Uma visão pode referenciar outra visão em sua definição. Dizemos que a visão v₁ depende diretamente de v₂ quando v₂ é usada na expressão que define v₁, e que v₁ depende de v₂ se há uma cadeia de dependências entre elas.

Visão de professores de tempo integral de cada escola (usa a visão professores_publico):

CREATE OR REPLACE VIEW professores_40h AS
SELECT id_prof, nome, id_escola
FROM   professores_publico
WHERE  ch_semanal = 40;

Consulta que usa a visão derivada:

SELECT e.sigla AS escola, p.nome AS professor
FROM   professores_40h p
JOIN   escola e USING (id_escola)
ORDER BY e.sigla, p.nome;
4 records
escola professor
EEMA Felipe Araujo
ESETI Helena Carvalho
ESG Bruno Teixeira
ESG Carla Pinto

Expansão de Visão

Quando uma consulta usa uma visão, o SGBD substitui a referência à visão pela expressão de consulta que a define — processo chamado de expansão de visão. Isso se repete recursivamente até que nenhuma visão permaneça na expressão final.

A expansão funciona substituindo iterativamente cada visão vᵢ encontrada na expressão e₁ pela sua definição. O processo termina quando não há mais visões na expressão — desde que as definições não sejam recursivas.

Visões Materializadas

Uma visão materializada (materialized view) é uma visão cujo resultado é fisicamente armazenado no banco de dados. Diferentemente de uma visão comum, ela ocupa espaço em disco e precisa ser mantida (atualizada) quando as tabelas subjacentes mudam.

O PostgreSQL suporta visões materializadas com CREATE MATERIALIZED VIEW. O refresco é manual com REFRESH MATERIALIZED VIEW.

CREATE MATERIALIZED VIEW IF NOT EXISTS mv_desempenho_aluno AS
SELECT a.id_aluno, a.nome, a.id_curso,
       COUNT(*)                                       AS disciplinas_cursadas,
       ROUND(AVG(md.nota), 2)                        AS media_geral,
       SUM(CASE WHEN md.aprovado = 1 THEN 1 ELSE 0 END) AS aprovacoes
FROM   aluno a
JOIN   matricula_disciplina md USING (id_aluno)
WHERE  md.nota IS NOT NULL
GROUP BY a.id_aluno, a.nome, a.id_curso;
-- Consultando a visão materializada
SELECT nome, media_geral, aprovacoes, disciplinas_cursadas
FROM   mv_desempenho_aluno
ORDER BY media_geral DESC NULLS LAST;
Displaying records 1 - 10
nome media_geral aprovacoes disciplinas_cursadas
Beatriz Carvalho 9.30 2 2
Camila Teixeira 8.00 2 2
Carolina Lima 8.00 4 4
Letícia Souza 7.90 2 2
Rafael Costa 7.75 4 4
Amanda Moreira 7.70 6 6
Gabriel Ribeiro 7.25 4 4
Matheus Silva 7.22 5 6
Rodrigo Lima 6.60 2 2
Vinícius Pereira 6.55 2 2
-- Refresco manual (atualiza a visão com os dados atuais das tabelas base)
REFRESH MATERIALIZED VIEW mv_desempenho_aluno;

Atualização de Visões

Em geral, uma visão só pode ser atualizada (suportar INSERT, UPDATE, DELETE) quando satisfaz certas condições que garantem que a operação pode ser traduzida univocamente para a tabela base.

Uma visão é considerada atualizável pelo SQL quando:

  • A cláusula FROM contém apenas uma tabela base.
  • A cláusula SELECT contém apenas nomes de atributos (sem expressões, agregações ou DISTINCT).
  • Todo atributo não listado no SELECT pode receber NULL.
  • A consulta não contém GROUP BY nem HAVING.

A visão professores_publico é atualizável — contém uma única tabela base e apenas nomes de colunas. No entanto, inserir via ela exige que salario (não exposto) aceite NULL:

-- Insere um professor novo pela visão (salario ficará NULL na tabela base)
INSERT INTO professores_publico (id_prof, nome, id_escola, ch_semanal)
VALUES (31200004, 'Julia Mendes', 31, 20);

Visões como salario_escola (que usam GROUP BY) não são atualizáveis. Tentativas de inserção ou atualização direta são rejeitadas pelo SGBD.


Para Praticar

-- Visão de disciplinas com pré-requisitos: mostra o nome de ambas
CREATE OR REPLACE VIEW v_prereqs AS
SELECT d.id_disciplina,
       d.nome_disciplina              AS disciplina,
       dp.nome_disciplina             AS prerequisito,
       d.id_curso,
       d.semestre
FROM   prereq pr
JOIN   disciplina d  ON d.id_disciplina  = pr.id_disciplina
JOIN   disciplina dp ON dp.id_disciplina = pr.id_prereq;
-- Usando a visão para listar pré-requisitos do curso ENS
SELECT disciplina, prerequisito, semestre
FROM   v_prereqs
WHERE  id_curso = 311
ORDER BY semestre, disciplina;
8 records
disciplina prerequisito semestre
Bases da Eng. de Software 4 Bases da Eng. de Software 2 4
Projeto Aplicado 4 - blockchain Projeto Aplicado 2 - site WEB 4
Bases da Eng. de Software 6 Bases da Eng. de Software 4 6
Bases da Eng. de Software 6 Projeto Aplicado 4 - blockchain 6
Projeto Aplicado 6 - Machine Learning Projeto Aplicado 4 - blockchain 6
Bases da Eng. de Software 8 Bases da Eng. de Software 6 8
Projeto Aplicado 8 - Sistema em Tempo Real Bases da Eng. de Software 6 8
Projeto Aplicado 8 - Sistema em Tempo Real Projeto Aplicado 6 - Machine Learning 8
-- Visão de alunos reprovados com informação do curso
CREATE OR REPLACE VIEW v_alunos_reprovados AS
SELECT a.nome AS aluno, c.sigla_curso, d.nome_disciplina,
       md.nota, md.ano, md.semestre
FROM   matricula_disciplina md
JOIN   aluno      a USING (id_aluno)
JOIN   disciplina d USING (id_disciplina)
JOIN   curso      c ON c.id_curso = a.id_curso
WHERE  md.aprovado = 0;
SELECT * FROM v_alunos_reprovados ORDER BY sigla_curso, aluno;
7 records
aluno sigla_curso nome_disciplina nota ano semestre
Fernanda Martins ECO História Econômica Geral 3.4 2024 2
Isabela Freitas ENS Projeto Aplicado 4 - blockchain 0.4 2025 2
Isabela Freitas ENS Bases da Eng. de Software 2 4.3 2024 2
Juliana Nunes ENS Bases da Eng. de Software 2 1.9 2025 2
Larissa Araújo ENS Bases da Eng. de Software 6 0.3 2025 2
Matheus Silva ENS Bases da Eng. de Software 6 4.1 2025 2
Thiago Gomes PED Eletiva II 1.3 2025 2