Veja nesse artigo como utilizar Views simples e Views materializadas no banco de dados PostgreSQL 9.4.
Artigos Banco de Dados Como funcionam as Views no PostgreSQL
CREATE [ OR REPLACE ] [ TEMP | TEMPORARY ] [ RECURSIVE ] VIEW name
A instrução CREATE [ OR REPLACE ] VIEW é semelhante a anterior, mas verifica se já existe uma view com o mesmo nome e, caso exista, será substituída pela mais recente. O nome dado a nova view não pode ser o mesmo já atribuído também a qualquer outro item presente no banco.
Caso o nome do Schema tenha sido fornecido, a View será criada com base nele e não no Schema global. Quando temos um Schema sendo especificado, este não pode ser temporário, assim como as Views.
O parâmetro [ TEMPORARY | TEMP ] é especificado quando queremos que a View seja temporária, as quais são eliminadas de forma automática quando a sessão atual é finalizada. Caso tenhamos referenciado tabelas temporárias para a View, esta será criada como temporária mesmo que não tenhamos especificado este parâmetro.
Já o RECURSIVE cria Views recursivas, ou seja, aquelas que trabalham dentro delas próprias, como na sintaxe a seguir:
Podemos também utilizar a seguinte sintaxe, que é uma versão reduzida:
Um exemplo real da aplicação desse conceito seria ter uma tabela de usuários, onde procuraríamos dentre estes quais são administradores:
CREATE VIEW administradores AS WITH RECURSIVE usuarios (columns) AS (SELECT ...) SELECT isAdministrador FROM usuarios;
O Name é o nome da View, podendo este ser opcional já o column_name, que é uma lista opcional que contém os nomes a serem utilizados para as colunas da View.
O check_option (string), pode ser local ou em cascata, e é equivalente à quando especificamos o WITH [CASCADED | LOCAL] CHECK OPTION. Esta opção pode ser alterada em Views existentes quando utilizamos a instrução ALTER VIEW. O security_barrier (string) é utilizado quando a View é criada com o intuito de fornecer segurança a nível de linha.
O WITH [ CASCADE | LOCAL] CHECK OPTION é uma opção utilizada para controle do comportamento da View com base nas atualizações automáticas. No caso desta opção ser especificada, os comandos de Insert e Update são verificados para garantir que as novas linhas satisfaçam as condições que definem a View. Caso não estejam em conformidade, a atualização não ocorrerá. Caso o CHECK OPTION não seja especificado, os comandos INSERT e UPDATE presentes na View serão autorizados a criar linhas não visíveis através da View.
As opções de verificação suportadas, são as seguintes:
LOCAL – onde novas linhas são verificadas apenas contra as condições definidas diretamente na própria View.
CASCADED – aqui novas linhas são verificadas em relação às condições da View e todas as Views subjacentes.
Se a cláusula CHECK OPTION for especificada e não tivermos a especificação da LOCAL nem da CASCADED, então o CASCADED é assumido. Precisamos ter cuidado apenas com as Views recursivas, pois o CHECK OPTION não pode ser utilizado nelas. Ou seja, esse parâmetro só é suportado apenas em Views que são atualizadas automaticamente e não possuem triggers do tipo Instead Of ou mesmo que contenham regras do tipo Instead. Se uma View que é atualizada automaticamente for definida com base em uma View que contenha uma trigger Instead of, então a LOCAL CHECK OPTION pode ser utilizada para verificar as condições sobre esta View, mas as condições referentes a View que contém a trigger INSTEAD OF não será verificada.
Vamos criar uma tabela funcionarios que será responsável por manter os registros reais, como mostra a Listagem 2.
"codFunc" integer NOT NULL,
CONSTRAINT "codFuncFK" FOREIGN KEY ("codFunc")
-- Index: "fki_codFuncFK"
-- DROP INDEX "fki_codFuncFK";
CREATE INDEX "fki_codFuncFK"
CREATE VIEW View_Ponto_funcionario AS SELECT nome_func, profissao, entrada, hora_entrada FROM funcionarios, registro_ponto WHERE funcionarios.codigo = registro_ponto."codFunc";
INSERT INTO funcionarios(codigo, nome_func, data_entrada, profissão, salario) VALUES (1, 'Edson Dionisio', '2015-09-01', 'Desenvolvedor Web', 2000.00);
INSERT INTO funcionarios(codigo, nome_func, data_entrada, profissao) VALUES (2, 'Marília Késsia', '2013-02-01', 'Coordenadora', 5000.00);
INSERT INTO funcionarios(codigo, nome_func, data_entrada, profissao) VALUES (3, 'Caroline França', '2015-06-15', 'Estéticista', 2500.00);
INSERT INTO registro_ponto(registro_ponto_id, entrada, hora_entrada, "codFunc") VALUES (1, '2015-10-03', '13:00:00', 1);
INSERT INTO registro_ponto(registro_ponto_id, entrada, hora_entrada, "codFunc") VALUES (2, '2015-11-04', '08:00:00', 2);
INSERT INTO registro_ponto(registro_ponto_id, entrada, hora_entrada, "codFunc") VALUES (3, '2015-10-05', '08:00:00', 1);
Feita a inserção dos dados, podemos ver as mudanças na nossa segunda View utilizando a seguinte instrução:
Como mostra a Figura 1, as informações sendo apresentadas na View contendo os dados solicitados das duas tabelas.
Trabalhando com as Views materializadas
Como as Views são apenas para leitura e representação lógica dos dados que estão armazenados nas tabelas do banco de dados, podemos "materializadas", ou seja, armazená-las fisicamente no disco.
Ao contrário da View tradicional, que nos apresentam dados atualizados automaticamente, as Views materializadas precisam de um mecanismo de atualização. A sintaxe é apresentada na Listagem 5.
Listagem 5. Sintaxe básica de uma View materializada.
A instrução CREATE MATERIALIZED VIEW cria View e a consulta é executada para preenche-la. Para atualizar os dados usamos o comando REFRESH MATERIALIZED VIEW. Uma View materializada tem muitas das mesmas propriedades de uma tabela, mas não há suporte para materialização temporária ou geração automática de OIDs.
O parâmetro TABLESPACE tablespace_name é o nome do espaço de tabelas no qual a nova View materializada deve ser criada. Se este não for especificado, a consulta será realizada no default_tablespace.
Com base no exemplo que desenvolvemos nesse artigo, a instrução a seguir cria uma view materializada para a tabela funcionarios:
INSERT INTO funcionarios (codigo, nome_func, data_entrada, profissao) VALUES (5, 'Gustavo França', '2014-10-11', 'Estagiário');
INSERT INTO funcionarios (codigo, nome_func, data_entrada, profissao) VALUES (6, 'Mayara Silva', '2015-06-10', 'Analista de testes');
INSERT INTO funcionarios (codigo, nome_func, data_entrada, profissao) VALUES (7, 'João dos testes', '2011-01-01', 'Gerente de negócios');
INSERT INTO funcionarios (codigo, nome_func, data_entrada, profissao) VALUES (8, 'Marina França', '2012-03-07', 'Analista de negócios');
INSERT INTO funcionarios (codigo, nome_func, data_entrada, profissao) VALUES (9, 'Paulo Dionisio', '2013-07-07', 'DBA Sênior');
Agora utilizaremos o comando SELECT para verificarmos se os registros foram realmente inseridos com sucesso:
Podemos ver que obtivemos um erro ao tentarmos consultar a nossa View, como mostra a Figura 2.
Feito isso, e em seguida, tentando consultar novamente os dados e assim obtemos êxito.
Para que isso ocorra, um índice exclusivo passa a ser necessário para existir na View materializada. Sendo assim, ao executarmos o comando select novamente, teremos todos os dados atualizados, como podemos ver na Figura 3.
DROP MATERIALIZED VIEW view_materializada_funcionario;
Todos os recursos de otimização são importantes, pois lembre-se que as views são apenas visões dos dados e são carregadas apenas quando necessárias. Mas elas criam uma camada extra para administrar e podem limitar exageradamente, impedindo certas tarefas.