Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

desafio do final da aula de trigger

Refiz a trigger com a alteração de salario se o instrutor receber mais que 100% dos instrutores, alterando o salário para ficar igual ao maior salario registrado... mas estou errando no retorno.

create or replace function cria_instrutor() returns trigger as $$
    declare
    media_salarial decimal default 0;
    instrutores_recebem_menos integer default 0;
    total_instrutores integer default 0;
    salario decimal default 0;
    percentual decimal(5,2) default 0;
    begin

        select avg(instrutor.salario) into media_salarial from instrutor where id <> new.id;

        if new.salario > media_salarial then
            insert into log_instrutores (informacao) values (new.nome || ' recebe acima da média ');
        end if;

    for salario in select  instrutor.salario from instrutor where id <> new.id loop
        total_instrutores = total_instrutores +1;

        if new.salario > salario then
            instrutores_recebem_menos = instrutores_recebem_menos +1;
        end if;
    end loop;

        percentual = instrutores_recebem_menos::decimal / total_instrutores::decimal * 100;

    if percentual = 100 then
        return new.salario = (select instrutor.salario from instrutor order by salario desc limit 1);
        insert into log_instrutores (informacao) values
            (new.nome || ' teve o salario anterado para o teto da categoria = ' || new.salario);
        return new;
    else    
        insert into log_instrutores (informacao) values 
            (new.nome || ' recebe mais que ' || percentual || '% da grade de instrutores');
        RETURN NEW;
    end if;
    end;
$$ language plpgsql;
create trigger cria_log_instrutores before insert on instrutor
    for each row execute function cria_instrutor();

A alteração que fiz foi nessa parte

if percentual = 100 then
        return new.salario = (select instrutor.salario from instrutor order by salario desc limit 1);
        insert into log_instrutores (informacao) values
            (new.nome || ' teve o salario anterado para o teto da categoria = ' || new.salario);
        return new;
    else    
        insert into log_instrutores (informacao) values 
            (new.nome || ' recebe mais que ' || percentual || '% da grade de instrutores');
        RETURN NEW;
    end if;

O resultado que recebo quando faço o insert into instrutor (nome, salario) values ('Tiago Oliveira', 1200);

ERROR: não pode retornar valor não-composto de função que retorna tipo composto CONTEXT: função PL/pgSQL cria_instrutor() linha 27 em RETURN SQL state: 42804

2 respostas
solução!

Oiii Tiago, como você está?

Peço desculpas pela demora em obter um retorno.

O erro está acontecendo por causa da seguinte linha:

return new.salario = (select instrutor.salario from instrutor order by salario desc limit 1);

Não é necessário utilizar a palavra chave return, pois você está atribuindo um valor ao novo salário. Apenas a cláusula return NEW ao final já é suficiente para retornar as informações modificadas. Sendo assim, altere para:

new.salario = (select instrutor.salario from instrutor order by salario desc limit 1);

Após essa alteração, apague a função e a trigger e às crie novamente:

DROP TRIGGER IF EXISTS cria_log_instrutores ON instrutor;
DROP FUNCTION IF EXISTS cria_instrutor();

Agora, ao executar o insert e fazer um select nas tabelas de instrutor e log_instrutores, veja que obterá o resultado esperado, como mostro abaixo:

Imagem com o fundo branco e que mostra o resultado do select na tabela log_instrutores, onde a mesma informa que Tiago recebe acima da média e teve o salário alterado para o teto da categoria

Ponto de atenção em relação a seu código: Caso sua tabela de instrutor não tenha nenhum dado e o primeiro a ser inserido seja o insert into instrutor (nome, salario) values ('Tiago Oliveira', 1200);, um erro de division by zero será gerado, pois o valor de total_instrutores começa com zero e divisões por zero, matematicamente falando não existem. A divisão é feita na seguinte linha:

percentual = instrutores_recebem_menos::decimal / total_instrutores::decimal * 100;

Para corrigir isso, algo que pode fazer é criar uma condição para que quando o valor total_instrutores for zero, modificá-lo para 1. Da seguinte forma:

IF total_instrutores = 0 THEN 
total_instrutores = 1;
ELSE 
percentual = instrutores_recebem_menos::decimal / total_instrutores::decimal * 100;
END IF;

Como o valor será 0 apenas quando a tabela for vazia, você não terá maiores problemas.

Qualquer dúvida fico à disposição.

Abraços e bons estudos!

Muito obrigado Nádia, eu apliquei as suas orientações e deu certo, Valeu!