└── exercicios_prova.sql /exercicios_prova.sql: -------------------------------------------------------------------------------- 1 | -- Exercício 1: UDF 2 | -- Considere a tabela livro (id, livro, tipo). Construa essa tabela e insira 5 livros. Escreva uma função (UDF) para auxiliar o cálculo da 3 | -- data de devolução de um livro em uma biblioteca. Exemplifique comandos SQL que usem essa função (e.g. SELECT, INSERT,UPDATE). 4 | -- Considere que: 5 | -- se o livro for MUITOPROCURADO, a devolução deve ocorrer no dia seguinte ao empréstimo; 6 | -- se o livro for POUCOPROCURADO, a devolução deve ser três dias depois do empréstimo; 7 | -- se o livro for RARAMENTEPROCURADO, a devolução deve ocorrer cinco dias após o empréstimo. 8 | -- Dica: estudar sobre o tipo timestamp, as funções now() e age(), e intervalos. 9 | -- Nota: 10 | -- date + integer → date 11 | -- Add a number of days to a date 12 | -- date '2021-09-28' + 7 → 2021-10-05 13 | 14 | CREATE TABLE livro ( 15 | id SMALLINT NOT NULL, 16 | livro VARCHAR(60) NOT NULL, 17 | tipo VARCHAR(60) 18 | ); 19 | 20 | insert into livro(id, livro, tipo) values (1, 'Cachorro', 'MUITOPROCURADO'); 21 | insert into livro(id, livro, tipo) values (2, 'Gato', 'MUITOPROCURADO'); 22 | insert into livro(id, livro, tipo) values (3, 'Cavalo', 'POUCOPROCURADO'); 23 | insert into livro(id, livro, tipo) values (4, 'Jacare', 'POUCOPROCURADO'); 24 | insert into livro(id, livro, tipo) values (5, 'vaca', 'RARAMENTEPROCURADO'); 25 | 26 | SELECT CURRENT_DATE; 27 | 28 | Create or replace function devolucao (um_id INT) returns date AS $$ 29 | declare 30 | um_tipo livro.tipo%type; 31 | begin 32 | select l.tipo into um_tipo 33 | from livro l 34 | where l.id = um_id; 35 | 36 | if um_tipo = 'MUITOPROCURADO' THEN 37 | return current_date + 1; 38 | end if; 39 | 40 | if um_tipo = 'POUCOPROCURADO' THEN 41 | return current_date + 3; 42 | end if; 43 | 44 | if um_tipo = 'RARAMENTEPROCURADO' THEN 45 | return current_date + 5; 46 | end if; 47 | 48 | end; 49 | $$ language 'plpgsql'; 50 | 51 | ---------------------------------------------------------------------------------- 52 | 53 | -- Exercicio 2 54 | 55 | CREATE OR REPLACE PROCEDURE registrar_info_empregado(um_cpf VARCHAR, qtde_dep INT, depto BIGINT, projetos BIGINT) 56 | AS $$ 57 | BEGIN 58 | IF EXISTS(SELECT cpf FROM info_empregado WHERE cpf=um_cpf) THEN 59 | UPDATE info_empregado SET 60 | data_hora = CURRENT_TIMESTAMP, 61 | qtde_dependentes = qtde_dep, 62 | depto_atual = depto, 63 | qtde_projetos = projetos 64 | WHERE cpf = um_cpf; 65 | ELSE 66 | INSERT INTO info_empregado 67 | VALUES (um_cpf, CURRENT_TIMESTAMP, qtde_dep, depto, projetos); 68 | END IF; 69 | END; 70 | $$ LANGUAGE 'plpgsql'; 71 | CALL registrar_info_empregado('123.456.789-55', 5, 1, 10); 72 | SELECT * FROM info_empregado; 73 | -- Database: exercicio 74 | -- DROP DATABASE exercicio; 75 | CREATE DATABASE exercicio 76 | WITH 77 | OWNER = postgres 78 | ENCODING = 'UTF8' 79 | LC_COLLATE = 'Portuguese_Brazil.1252' 80 | LC_CTYPE = 'Portuguese_Brazil.1252' 81 | TABLESPACE = pg_default 82 | CONNECTION LIMIT = -1; 83 | -- Table: public.info_empregado 84 | -- DROP TABLE public.info_empregado; 85 | CREATE TABLE IF NOT EXISTS public.info_empregado 86 | ( 87 | cpf character varying COLLATE pg_catalog."default" NOT NULL, 88 | data_hora date NOT NULL, 89 | qtde_dependentes bigint, 90 | depto_atual bigint, 91 | qtde_projetos bigint, 92 | CONSTRAINT info_empregado_pkey PRIMARY KEY (cpf) 93 | ) 94 | TABLESPACE pg_default; 95 | ALTER TABLE public.info_empregado 96 | OWNER to postgres; 97 | -- Table: public.livro 98 | -- DROP TABLE public.livro; 99 | CREATE TABLE IF NOT EXISTS public.livro 100 | ( 101 | id bigint NOT NULL, 102 | livro character varying COLLATE pg_catalog."default" NOT NULL, 103 | tipo character varying COLLATE pg_catalog."default" NOT NULL, 104 | CONSTRAINT livro_pkey PRIMARY KEY (id) 105 | ) 106 | TABLESPACE pg_default; 107 | ALTER TABLE public.livro 108 | OWNER to postgres; 109 | 110 | ---------------------------------------------------------------------------------- 111 | 112 | -- Exercicio 3 113 | 114 | CREATE TABLE classificacao ( 115 | selecao_nome VARCHAR(60), 116 | grupo VARCHAR(1), 117 | pontos SMALLINT, 118 | jogos SMALLINT, 119 | vitorias SMALLINT, 120 | empates SMALLINT, 121 | derrotas SMALLINT, 122 | gols_pro SMALLINT, 123 | gols_contra SMALLINT, 124 | saldo_gols SMALLINT 125 | ); 126 | 127 | CREATE TABLE partida( 128 | nro_partida SMALLINT, 129 | grupo VARCHAR(1), 130 | selecao_mandante VARCHAR(30), 131 | gols_selecao_mandante SMALLINT, 132 | selecao_visitante VARCHAR(30), 133 | gols_selecao_visitante SMALLINT 134 | ); 135 | 136 | INSERT INTO classificacao(selecao_nome, grupo, pontos, jogos, vitorias, empates,derrotas,gols_pro, gols_contra, saldo_gols) VALUES ('Brasil', 'G', 0, 0, 0, 0, 0, 0, 0, 0); 137 | INSERT INTO classificacao(selecao_nome, grupo, pontos, jogos, vitorias, empates,derrotas,gols_pro, gols_contra, saldo_gols) VALUES ('Coréia do Norte', 'G', 0, 0, 0, 0, 0, 0, 0, 0); 138 | INSERT INTO classificacao(selecao_nome, grupo, pontos, jogos, vitorias, empates,derrotas,gols_pro, gols_contra, saldo_gols) VALUES ('Costa do Marfim', 'G', 0, 0, 0, 0, 0, 0, 0, 0); 139 | INSERT INTO classificacao(selecao_nome, grupo, pontos, jogos, vitorias, empates,derrotas,gols_pro, gols_contra, saldo_gols) VALUES ('Portugual', 'G', 0, 0, 0, 0, 0, 0, 0, 0); 140 | 141 | CREATE OR REPLACE FUNCTION tg_classificacao_trigger() 142 | RETURNS TRIGGER AS $$ 143 | BEGIN 144 | 145 | if new.gols_selecao_mandante > new.gols_selecao_visitante then 146 | UPDATE classificacao 147 | set pontos = pontos + 3, jogos = jogos + 1, vitorias = vitorias + 1, gols_pro = gols_pro + new.gols_selecao_mandante, 148 | gols_contra = gols_contra + new.gols_selecao_visitante, saldo_gols = saldo_gols + (gols_pro - gols_contra) 149 | where selecao_nome = new.selecao_mandante; 150 | 151 | UPDATE classificacao 152 | set jogos = jogos + 1, derrotas = derrotas + 1, gols_pro = gols_pro + new.gols_selecao_mandante, 153 | gols_contra = gols_contra + new.gols_selecao_visitante, saldo_gols = saldo_gols + (gols_pro - gols_contra) 154 | where selecao_nome = new.selecao_visitante; 155 | return new; 156 | end if; 157 | 158 | if new.gols_selecao_mandante < new.gols_selecao_visitante then 159 | UPDATE classificacao 160 | set pontos = pontos + 3, jogos = jogos + 1, vitorias = vitorias + 1, gols_pro = gols_pro + new.gols_selecao_mandante, 161 | gols_contra = gols_contra + new.gols_selecao_visitante, saldo_gols = saldo_gols + (gols_pro - gols_contra) 162 | where selecao_nome = new.selecao_visitante; 163 | 164 | UPDATE classificacao 165 | set jogos = jogos + 1, derrotas = derrotas + 1, gols_pro = gols_pro + new.gols_selecao_mandante, 166 | gols_contra = gols_contra + new.gols_selecao_visitante, saldo_gols = saldo_gols + (gols_pro - gols_contra) 167 | where selecao_nome = new.selecao_mandante; 168 | return new; 169 | end if; 170 | 171 | if new.gols_selecao_mandante = new.gols_selecao_visitante then 172 | UPDATE classificacao 173 | set pontos = pontos + 1, jogos = jogos + 1, empates = empates + 1, gols_pro = gols_pro + new.gols_selecao_mandante, 174 | gols_contra = gols_contra + new.gols_selecao_visitante, saldo_gols = saldo_gols + (gols_pro - gols_contra) 175 | where selecao_nome = new.selecao_visitante; 176 | 177 | UPDATE classificacao 178 | set pontos = pontos + 1, jogos = jogos + 1, empates = empates + 1, gols_pro = gols_pro + new.gols_selecao_mandante, 179 | gols_contra = gols_contra + new.gols_selecao_visitante, saldo_gols = saldo_gols + (gols_pro - gols_contra) 180 | where selecao_nome = new.selecao_mandante; 181 | return new; 182 | end if; 183 | 184 | 185 | RETURN NULL; 186 | END; 187 | $$ language 'plpgsql'; 188 | 189 | 190 | create trigger t_classificacao_trigger 191 | after insert on partida 192 | for each row execute function tg_classificacao_trigger(); 193 | 194 | INSERT INTO partida(nro_partida, grupo, selecao_mandante, gols_selecao_mandante, selecao_visitante, gols_selecao_visitante) VALUES (13, 'G', 'Costa do Marfim', 0, 'Portugal', 0); 195 | INSERT INTO partida(nro_partida, grupo, selecao_mandante, gols_selecao_mandante, selecao_visitante, gols_selecao_visitante) VALUES (14, 'G', 'Brasil', 2, 'Coréia do Norte', 1); 196 | 197 | 198 | ---------------------------------------------------------------------------------- 199 | 200 | -- Exercício 4 201 | 202 | -- A consulta seguinte é frequentemente executada no banco de dados empresa. 203 | -- SELECT projeto.nome as projeto_nome, count(*) as salarios_entre_2500e10000 204 | -- FROM projeto 205 | 206 | -- INNER JOIN trabalha_em ON projeto.numero=trabalha_em.proj_num 207 | 208 | -- INNER JOIN colaborador ON trabalha_em.cpf = colaborador.cpf 209 | 210 | -- WHERE colaborador.salario > 2500.00 AND colaborador.salario < 10000.01 211 | 212 | -- GROUP BY projeto.nome 213 | -- ORDER BY projeto.nome; 214 | 215 | -- a. Execute a consulta e mostre o plano e o relatório de execução. 216 | EXPLAIN ANALYZE 217 | SELECT projeto.nome as projeto_nome, count(*) as salarios_entre_2500e10000 218 | FROM projeto 219 | INNER JOIN trabalha_em ON projeto.numero=trabalha_em.proj_num 220 | INNER JOIN colaborador ON trabalha_em.cpf = colaborador.cpf 221 | WHERE colaborador.salario > 2500.00 AND colaborador.salario < 10000.01 222 | GROUP BY projeto.nome 223 | ORDER BY projeto.nome; 224 | 225 | -- b. Identifique a ordem das operações executadas. 226 | 227 | 1 GroupAggregate (cost=3.66..3.68 rows=1 width=56) 228 | 2 Group Key: projeto.nome 229 | 3 -> Sort (cost=3.66..3.67 rows=1 width=48) 230 | 4 Sort Key: projeto.nome 231 | 5 -> Hash Join (cost=2.50..3.65 rows=1 width=48) 232 | 6 Hash Cond: (projeto.numero = trabalha_em.proj_num) 233 | 7 -> Seq Scan on projeto (cost=0.00..1.10 rows=10 width=50) 234 | 8 -> Hash (cost=2.49..2.49 rows=1 width=2) 235 | 9 -> Hash Join (cost=1.40..2.49 rows=1 width=2) 236 | 10 Hash Cond: (trabalha_em.cpf = colaborador.cpf) 237 | 11 -> Seq Scan on trabalha_em (cost=0.00..1.07 rows=7 width=62) 238 | 12 -> Hash (cost=1.39..1.39 rows=1 width=60) 239 | 13 -> Seq Scan on colaborador (cost=0.00..1.39 rows=1 width=60) 240 | 14 Filter: ((salario > 2500.00) AND (salario < 10000.01)) 241 | 242 | Ordem: (13), (12,11), (9), (8,7), (5), (3), (1) 243 | 244 | -- c. Identifique a operação mais custosa individualmente. 245 | Linhas 12, 9, 8, 5, 3, 1; 246 | 247 | -- d. Identifique a operação mais demorada individualmente. 248 | 249 | GroupAggregate (cost=3.66..3.68 rows=1 width=56) (actual time=0.381..0.388 rows=2 loops=1) 250 | Group Key: projeto.nome 251 | -> Sort (cost=3.66..3.67 rows=1 width=48) (actual time=0.366..0.371 rows=3 loops=1) 252 | Sort Key: projeto.nome 253 | Sort Method: quicksort Memory: 25kB 254 | -> Hash Join (cost=2.50..3.65 rows=1 width=48) (actual time=0.248..0.259 rows=3 loops=1) 255 | Hash Cond: (projeto.numero = trabalha_em.proj_num) 256 | -> Seq Scan on projeto (cost=0.00..1.10 rows=10 width=50) (actual time=0.054..0.056 rows=10 loops=1) 257 | -> Hash (cost=2.49..2.49 rows=1 width=2) (actual time=0.171..0.174 rows=3 loops=1) 258 | Buckets: 1024 Batches: 1 Memory Usage: 9kB 259 | -> Hash Join (cost=1.40..2.49 rows=1 width=2) (actual time=0.153..0.164 rows=3 loops=1) 260 | Hash Cond: (trabalha_em.cpf = colaborador.cpf) 261 | -> Seq Scan on trabalha_em (cost=0.00..1.07 rows=7 width=62) (actual time=0.028..0.030 rows=8 loops=1) 262 | -> Hash (cost=1.39..1.39 rows=1 width=60) (actual time=0.085..0.086 rows=12 loops=1) 263 | Buckets: 1024 Batches: 1 Memory Usage: 9kB 264 | -> Seq Scan on colaborador (cost=0.00..1.39 rows=1 width=60) (actual time=0.048..0.067 rows=12 loops=1) 265 | Filter: ((salario > 2500.00) AND (salario < 10000.01)) 266 | Rows Removed by Filter: 16 267 | 268 | O GroupAggregate é a operação mais demorada individualmente, time = 0.381. 269 | 270 | -- e. Quais colunas envolvidas nessa consulta já possuem índices? Por quê? 271 | List of relations 272 | Schema | Name | Type | Owner | Table 273 | --------+---------------------+-------+----------+-------------- 274 | public | colaborador_pk | index | postgres | colaborador 275 | public | dependente_pf | index | postgres | dependente 276 | public | depto_nome_unique | index | postgres | departamento 277 | public | depto_pk | index | postgres | departamento 278 | public | edificios_pk | index | postgres | edificios 279 | public | projeto_nome_unique | index | postgres | projeto 280 | public | projeto_pk | index | postgres | projeto 281 | public | trabalha_em_pk | index | postgres | trabalha_em 282 | 283 | As colunas com indice envolvidas nessa pesquisa são: colaborador, trabalha_em, projeto. 284 | 285 | -- f. Caso a cláusula WHERE da consulta possa ter o desempenho do processamento melhorado, por meio da criação de um índice, qual seria o tipo desse índice? Por quê? 286 | 287 | EXPLAIN ANALYZE 288 | SELECT projeto.nome as projeto_nome, count(*) as salarios_entre_2500e10000 289 | FROM projeto 290 | INNER JOIN trabalha_em ON projeto.numero=trabalha_em.proj_num 291 | INNER JOIN colaborador ON trabalha_em.cpf = colaborador.cpf 292 | WHERE colaborador.salario > 2500.00 AND colaborador.salario < 10000.01 293 | GROUP BY projeto.nome 294 | ORDER BY projeto.nome; 295 | 296 | B+-tree 297 | - Consultas por igualdade 298 | - Consultas por por intervalo 299 | 300 | -- g. Redija o comando CREATE INDEX correspondente. 301 | 302 | CREATE INDEX colaborador_salario ON colaborador 303 | USING BTREE (salario); 304 | 305 | -- h. Execute a consulta e mostre o plano e o relatório de execução. Verifique se o índice foi usado. 306 | 307 | -- Não foi usado. 308 | 309 | -- i. Caso não tenha sido, use parâmetros de configuração para "forçar" seu uso. 310 | 311 | SET enable_sort = off; 312 | SET enable_indexscan = on; 313 | 314 | -- j. Execute ANALYZE; para atualizar as estatísticas do SGBD. Logo após, execute novamente a consulta e e mostre o plano e o relatório de execução. Compare o tempo para o 315 | -- processamento da cláusula WHERE nesta execução com o tempo das execuções anteriores. Comente se este tempo foi menor que aqueles anteriores. 316 | 317 | -- Sim, foi menor. 318 | 319 | ---------------------------------------------------------------------------------- 320 | 321 | -- Exercício 5 322 | 323 | -- Acesso remoto 324 | -- - Redija as linhas do arquivo pg_hba.conf de modo que 325 | -- - analista acesse o servidor a partir de endereços cujo prefixo é 192.168.55 326 | -- - gestao idem 327 | -- - sec_depto25 acesse o servidor a partir do endereço 192.168.55.125 328 | -- - sec_depto25 acesse o servidor a partir do endereço 192.168.55.177 329 | -- - Esses acessos só podem ser autorizados mediante apresentação de senha criptografada 330 | 331 | --------------------------------------------------------------------------------