{"id":15187469,"url":"https://github.com/andreadcsousa/alura_postgresql-plpgsql_sql","last_synced_at":"2026-02-11T21:02:41.328Z","repository":{"id":168043344,"uuid":"617006409","full_name":"andreadcsousa/alura_postgresql-plpgsql_sql","owner":"andreadcsousa","description":"Este projeto faz parte do plano de estudos elaborado pela Alura para o programa de formação Desenvolve (3ª edição), trilha de dados, em parceria com a Boticário.","archived":false,"fork":false,"pushed_at":"2023-03-21T14:19:00.000Z","size":244,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-07T06:22:58.842Z","etag":null,"topics":["alura","aprendendo","boticario","dados","desenvolve-2023","desenvolve-3-edicao","plpgsql","postgresql","sql"],"latest_commit_sha":null,"homepage":"","language":"PLpgSQL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andreadcsousa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-21T14:15:38.000Z","updated_at":"2023-03-21T14:17:09.000Z","dependencies_parsed_at":"2023-07-16T13:31:19.534Z","dependency_job_id":null,"html_url":"https://github.com/andreadcsousa/alura_postgresql-plpgsql_sql","commit_stats":{"total_commits":2,"total_committers":1,"mean_commits":2.0,"dds":0.0,"last_synced_commit":"60b7baa6e1b66824562d0474ce9bf9ac47b821f7"},"previous_names":["andreadcsousa/alura_postgresql-plpgsql_sql"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/andreadcsousa/alura_postgresql-plpgsql_sql","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreadcsousa%2Falura_postgresql-plpgsql_sql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreadcsousa%2Falura_postgresql-plpgsql_sql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreadcsousa%2Falura_postgresql-plpgsql_sql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreadcsousa%2Falura_postgresql-plpgsql_sql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andreadcsousa","download_url":"https://codeload.github.com/andreadcsousa/alura_postgresql-plpgsql_sql/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andreadcsousa%2Falura_postgresql-plpgsql_sql/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29345401,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-11T20:11:40.865Z","status":"ssl_error","status_checked_at":"2026-02-11T20:10:41.637Z","response_time":97,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alura","aprendendo","boticario","dados","desenvolve-2023","desenvolve-3-edicao","plpgsql","postgresql","sql"],"created_at":"2024-09-27T18:23:00.578Z","updated_at":"2026-02-11T21:02:41.294Z","avatar_url":"https://github.com/andreadcsousa.png","language":"PLpgSQL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PostgreSQL: desenvolva com PL/pgSQL\n\nImplementando Stored Procedures; utilizando cursores para buscar dados; controlando o fluxo da procedure; tratando os erros corretamente; aplicando e praticando programação com Stored Procedures.\n\n1. [Criando funções](#1-criando-funções)\n2. [Tipos e funções](#2-tipos-e-funções)\n3. [Linguagem Procedural](#3-linguagem-procedural)\n4. [Estruturas de Controle](#4-estruturas-de-controle)\n5. [Estruturas de repetição](#5-estruturas-de-repetição)\n6. [Mão na massa](#6-mão-na-massa)\n\nSaiba mais sobre o curso [aqui](https://cursos.alura.com.br/course/postgresql-procedures) ou acompanhe minhas anotações abaixo. ⬇️\n\n## 1. Criando funções\n\nPara programar com banco de dados, utilizam-se funções. As funções são uma extensão da linguagem SQL para complementar as consultas. A linguagem SQL não é uma linguagem de programação, pois não possui estruturas de decisão, repetição, variáveis, etc.\n\n### **Primeira função**\n\nO comando `CREATE FUNCTION` é utilizado para criar uma função que, em sua forma mais simples, não traz parâmetros e precisa retornar algo. Além disso, é preciso dizer a linguagem usada para criar a função.\n\n\u003e Por padrão, o nome da coluna retornada em uma função que nos entrega um único valor é o mesmo nome da função. Nós podemos facilmente mudar o nome dessa coluna utilizando o AS, que cria um alias.\n\n```sql\n-- Criando a função que retorna um inteiro usando a linguagem sql\nCREATE FUNCTION primeira_funcao() RETURNS INTEGER AS '\n\tSELECT (5 - 3) * 2\n' LANGUAGE SQL;\n\n-- Chama a função e retorna o inteiro com uma coluna de mesmo nome\nSELECT primeira_funcao();\n\n-- Chama a função e retorna o inteiro com uma coluna renomeada\nSELECT primeira_funcao() AS numero;\n\n-- É possível chamar a função como uma tabela também\nSELECT * FROM primeira_funcao();\n```\n\n### **Recebendo parâmetros**\n\nQuando utiliza-se parâmetros na função, o nome é opcional, mas é necessário dizer o tipo de dado que será usado. O nome é opcional, pois pode-se utilizar a posição do parâmetro na função criada.\n\n***Propósito do parâmetro no função:***\n\n\u003e Através de parâmetros nós podemos receber informações de fora da função (como o ID de um registro, por exemplo) e manipular estes dados dentro da função\n\n```sql\n-- Cria a função com dois parâmetros e seu tipo para utilizá-los inputando dados\nCREATE FUNCTION soma_dois_numeros(numero_1 INTEGER, numero_2 INTEGER)\nRETURNS INTEGER AS '\n\tSELECT numero_1 + numero_2\n' LANGUAGE SQL;\n\nSELECT soma_dois_numeros(2, 2);\n\n-- Uma das formas de reutilizar uma função é excluir e recriar ela\nDROP FUNCTION soma_dois_numeros;\n\n-- Cria a função com dois parâmetros só com o tipo de dado e utilizando sua posição\nCREATE FUNCTION soma_dois_numeros(INTEGER, INTEGER)\nRETURNS INTEGER AS '\n\tSELECT $1 + $2\n' LANGUAGE SQL;\n\nSELECT soma_dois_numeros(3, 17);\n```\n\n### **Detalhes sobre funções**\n\nO que define o valor que será retornado em uma função?\n\n    Após realizar todas as instruções, a última query tem seu resultado obtido pelo PostgreSQL\n    e, desse resultado, a primeira linha é retornada para quem chamou a função.\n\n- O último comando de uma função precisa informar o valor, precisa trazer o valor que se quer retornar.\n- O que vai ser utilizado como retorno é a primeira linha desse último comando. Sempre o primeiro item.\n\n```sql\nCREATE TABLE a (nome VARCHAR(255) NOT NULL);\n\nCREATE FUNCTION cria_a(nome VARCHAR) RETURNS VARCHAR AS '\n\tINSERT INTO a (nome) VALUES (cria_a.nome);\n\tSELECT nome;\n' LANGUAGE SQL;\n```\n\n***Restrição ao substituir uma função:***\n\n\u003e Nós não podemos alterar (REPLACE) uma função informando tipos diferentes em seus parâmetros ou retornos. Para atingir este objetivo precisamos excluir e criar esta função.\n\n```sql\n-- Alterando ou substituindo uma função, sem precisar excluir\nCREATE OR REPLACE FUNCTION cria_a(nome VARCHAR) RETURNS VARCHAR AS '\n\tINSERT INTO a (nome) VALUES (cria_a.nome);\n\tSELECT nome;\n' LANGUAGE SQL;\n\nSELECT cria_a('Vinicius Dias');\n```\n\nPara criar funções que não necessitam de um retorno, basta substituir o comando após o `RETURNS` para `void`. Isso faz com que, ao chamar a função, ela retorne um valor nulo.\n\nImportante saber que o comando void não permite replace, então é preciso excluir e recriar a função.\n\n```sql\nDROP FUNCTION cria_a;\n\nCREATE FUNCTION cria_a(nome VARCHAR) RETURNS void AS '\n\tINSERT INTO a (nome) VALUES (cria_a.nome);\n' LANGUAGE SQL;\n\nSELECT cria_a('Vinicius Dias');\n```\n\nQuando se quer definir um valor no insert como varchar, por exemplo, as aspas simples da função conflitam com as aspas simples do valor. Para resolver isso, existe outra forma de definir a criação da função. Utiliza-se `$$`.\n\n```sql\nDROP FUNCTION cria_a;\n\nCREATE FUNCTION cria_a(nome VARCHAR) RETURNS void AS $$\n\tINSERT INTO a (nome) VALUES ('Patrícia');\n$$ LANGUAGE SQL;\n```\n\nPara saber mais: [Procedure](Para%20saber%20mais/Aula%201%20-%20Atividade%2012%20Para%20saber%20mais_%20Procedure.pdf)\nPara saber mais: [Returning](Para%20saber%20mais/Aula%201%20-%20Atividade%2013%20Para%20saber%20mais_%20Returning.pdf)\n\n## 2. Tipos e funções\n\n### **Parâmetros compostos**\n\nAo utilizar uma tabela como parâmetro, define-se o campo que irá receber a função dentro da própria função.\n\n```sql\nCREATE TABLE instrutor (\n\tid SERIAL PRIMARY KEY,\n\tnome VARCHAR(255) NOT NULL,\n\tsalario DECIMAL(10, 2)\n);\n\nINSERT INTO instrutor (nome, salario) VALUES ('Vinicius Dias', 100);\n\nCREATE FUNCTION dobro_do_salario(instrutor) RETURNS DECIMAL AS $$\n\tSELECT $1.salario * 2 AS dobro;\n$$ LANGUAGE SQL;\n\nSELECT nome, dobro_do_salario(instrutor.*) FROM instrutor;\n```\n\n### **Retorno composto**\n\nO retorno composto utiliza os campos da tabela para trazer a primeira linha como um valor ou como um conjunto de valores.\n\n***Como um valor:***\n\n\u003e Usamos como um único valor quando o retorno da função for um tipo simples (após o SELECT).\n\n```sql\nCREATE OR REPLACE FUNCTION cria_instrutor_falso() RETURNS instrutor AS $$\n\tSELECT 22 AS id, 'Nome falso' AS nome, 200.00 AS salario;\n$$ LANGUAGE SQL;\n\nSELECT cria_instrutor_falso();\n```\n\n***Como um conjunto de valores:***\n\n\u003e Usamos como um conjunto de valores quando o retorno da função for um tipo composto (após o FROM).\n\n```sql\nCREATE OR REPLACE FUNCTION cria_instrutor_falso() RETURNS instrutor AS $$\n\tSELECT 22, 'Nome falso', 200::DECIMAL;\n$$ LANGUAGE SQL;\n\nSELECT * FROM cria_instrutor_falso();\n```\n\n- Ao criar a tabela, foi definido que o salário seria um valor decimal. Então, ao definir o salário na função é necessário que seja nesse formato. Acima estão duas formas de trazer tal notação.\n- Como a função está retornando a tabela instrutor como tipo, não é necessário colocar o nome dos campos na função, porém fica mais legível se tiverem descritos.\n\n### **Retornando conjuntos**\n\n```sql\n-- Inserindo mais dados na tabela\nINSERT INTO instrutor (nome, salario) VALUES ('Diogo Mascarenhas', 200);\nINSERT INTO instrutor (nome, salario) VALUES ('Nico Steppat', 300);\nINSERT INTO instrutor (nome, salario) VALUES ('Juliana Oliveira', 400);\nINSERT INTO instrutor (nome, salario) VALUES ('Príscila Saraiva', 500);\n\nCREATE FUNCTION instrutores_bem_pagos(valor_salario DECIMAL)\nRETURNS SETOF instrutor AS $$\n\tSELECT * FROM instrutor WHERE salario \u003e valor_salario;\n$$ LANGUAGE SQL;\n\nSELECT * FROM instrutores_bem_pagos(300);\n```\n\n\u003e Nós podemos definir a estrutura de uma tabela especificamente para o retorno de uma função. Isso é utilizado quando não queremos criar um tipo (ou tabela) específico para um retorno.\n\n```sql\nDROP FUNCTION instrutores_bem_pagos;\n\nCREATE FUNCTION instrutores_bem_pagos(valor_salario DECIMAL)\nRETURNS TABLE (id INTEGER, nome VARCHAR, salario DECIMAL) AS $$\n\tSELECT * FROM instrutor WHERE salario \u003e valor_salario;\n$$ LANGUAGE SQL;\n\nSELECT * FROM instrutores_bem_pagos(300);\n```\n\n- O record retorna uma linha genérica para o registro. Com ele é necessário definir as colunas que se quer retornar.\n\n```sql\nDROP FUNCTION instrutores_bem_pagos;\n\nCREATE FUNCTION instrutores_bem_pagos(valor_salario DECIMAL)\nRETURNS SETOF record AS $$\n\tSELECT * FROM instrutor WHERE salario \u003e valor_salario;\n$$ LANGUAGE SQL;\n\nSELECT * FROM instrutores_bem_pagos(300);\n```\n\n### **Parâmetros de saída**\n\nPode-se definir parâmetros de saída para retornar valores compostos. Além de definir os parâmetros de entrada no `IN`, o comando `OUT` funciona semelhante a criaçao de tipo para retornar valores compostos nos registros.\n\n```sql\n-- Utilizando parâmetros de saída para retornar valores compostos\nCREATE FUNCTION soma_e_produto (\n\tIN numero_1 INTEGER,\n\tIN numero_2 INTEGER,\n\tOUT soma INTEGER,\n\tOUT produto INTEGER\n) AS $$\n\tSELECT numero_1 + numero_2 AS soma, numero_1 * numero_2 AS produto;\n$$ LANGUAGE SQL;\n\nSELECT * FROM soma_e_produto(3, 3);\n\n-- Criando tipo para retornar valores compostos\nCREATE TYPE dois_valores AS (soma INTEGER, produto INTEGER);\n\nDROP FUNCTION soma_e_produto;\n\nCREATE FUNCTION soma_e_produto (IN numero_1 INTEGER, IN numero_2 INTEGER)\nRETURNS dois_valores AS $$\n\tSELECT numero_1 + numero_2 AS soma, numero_1 * numero_2 AS produto;\n$$ LANGUAGE SQL;\n\nSELECT * FROM soma_e_produto(3, 3);\n```\n\nEntão, para utilizar o `record` de maneira funcional, definindo as colunas que retornarão os registros, pode-se utilizar os parâmetros de saída em conjunto com ele.\n\n```sql\nDROP FUNCTION instrutores_bem_pagos;\n\nCREATE FUNCTION instrutores_bem_pagos(\n    valor_salario DECIMAL,\n    OUT nome VARCHAR,\n    OUT salario DECIMAL\n)\nRETURNS SETOF record AS $$\n\tSELECT nome, salario FROM instrutor WHERE salario \u003e valor_salario;\n$$ LANGUAGE SQL;\n\nSELECT * FROM instrutores_bem_pagos(300);\n```\n\n## 3. Linguagem procedural\n\n\u003e A PLPGSQL ou PL/pgSQL é uma linguagem estrutural estendida da SQL que tem por objetivo auxiliar as tarefas de programação no PostgreSQL. Ela incorpora à SQL características procedurais, como os benefícios e facilidades de controle de fluxo de programas que as melhores linguagens possuem. - [Wikipédia](https://pt.wikipedia.org/wiki/PLPGSQL)\n\n### **Estruturas de PLpgSQL**\n\nA estrutura PLpgSQL difere da estrutura SQL porque não, necessariamente, o último comando é executado. Na verdade, a PL precisa do `RETURN` para realmente retornar o que foi definido. Precisa também, das cláusulas `BEGIN` e `END` delimitando o corpo da função.\n\n```sql\nCREATE OR REPLACE FUNCTION primeira_pl() RETURNS INTEGER AS $$\n\tBEGIN\n        -- Vários comandos em SQL\n\t\tRETURN 1;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT primeira_pl();\n```\n\n***Diferenças básicas entre SQL e PLpgSQL:***\n\n- PLpgSQL informa de forma explícita o que vai retornar. Funções em SQL retornam o resultado da última query.\n- PLpgSQL precisa ter blocos definidos, enquanto funções em SQL não.\n\n### **Declarações de variáveis**\n\nO símbolo `:=` atribui um valor para uma variável. Difere do igual porque serve apenas para atribuição, enquanto o `=` pode ser utilizado para comparação. O `DEFAULT` funciona da mesma maneira, mas pode ser utilizado apenas para declarar a variável, dentro do corpo da função não funciona.\n\nPara saber mais: [Default](Para%20saber%20mais/Aula%203%20-%20Atividade%206%20Para%20saber%20mais_%20Default.pdf)\n\n```sql\nCREATE OR REPLACE FUNCTION primeira_pl() RETURNS INTEGER AS $$\n\tDECLARE\n\t\tprimeira_variavel INTEGER DEFAULT 3;\n\tBEGIN\n\t\tprimeira_variavel := primeira_variavel * 2;\n\t\tRETURN primeira_variavel;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT primeira_pl();\n```\n\n### **Blocos**\n\nCaso queira declarar uma variável dentro do bloco já existente, o PL entende como se fosse uma nova variável e apenas armazena ela.\n\n```sql\nCREATE OR REPLACE FUNCTION primeira_pl() RETURNS INTEGER AS $$\n\tDECLARE\n\t\tprimeira_variavel INTEGER DEFAULT 3;\n\tBEGIN\n\t\tprimeira_variavel := primeira_variavel * 2;\n\t\t\n\t\tDECLARE\n\t\t\tprimeira_variavel INTEGER;\n\t\tBEGIN\n\t\t\tprimeira_variavel := 7;\n\t\tEND;\n\t\t\n\t\tRETURN primeira_variavel;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT primeira_pl();\n```\n\nPara que essa variável se torne acessível dentro do bloco pai, basta não declará-la, apenas iniciar e finalizar já retorna seu valor.\n\n```sql\nCREATE OR REPLACE FUNCTION primeira_pl() RETURNS INTEGER AS $$\n\tDECLARE\n\t\tprimeira_variavel INTEGER DEFAULT 3;\n\tBEGIN\n\t\tprimeira_variavel := primeira_variavel * 2;\n\t\t\n\t\tBEGIN\n\t\t\tprimeira_variavel := 7;\n\t\tEND;\n\t\t\n\t\tRETURN primeira_variavel;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT primeira_pl();\n```\n\n\u003e Por padrão, por boas práticas, evite a todo custo definir duas variáveis com o mesmo nome em blocos diferentes.\n\nO que é um escopo de variáveis?\n\n    É o bloco onde uma variável “vive”. Fora deste bloco, ela não existe, ou seja, está fora de seu escopo.\n\n\u003e Uma variável declarada em um bloco mais interno não pode ser acessada em um bloco mais externo.\n\u003e Variáveis com o mesmo nome podem existir em diferentes escopos.\n\n## 4. Estruturas de controle\n\n### **Retornos em PLs**\n\n***Diferença no retorno do registro que vem vazio ao invés de nulo:***\n\n```sql\nDROP FUNCTION cria_a;\n\nCREATE OR REPLACE FUNCTION cria_a(nome VARCHAR) RETURNS void AS $$\n\tBEGIN\n\t\tINSERT INTO a (nome) VALUES ('Patricia');\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT cria_a('Vinicius Dias');\n```\n\n***Retorna uma linha com os registros, referenciando o tipo instrutor:***\n\n```sql\nCREATE OR REPLACE FUNCTION cria_instrutor_falso() RETURNS instrutor AS $$\n\tBEGIN\n\t\tRETURN ROW(22, 'Nome falso', 200::DECIMAL)::instrutor;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT id, salario FROM cria_instrutor_falso();\n```\n\n***Declara uma variável para inserir na consulta e retorna ela:***\n\n```sql\nCREATE OR REPLACE FUNCTION cria_instrutor_falso() RETURNS instrutor AS $$\n\tDECLARE\n\t\tretorno instrutor;\n\tBEGIN\n\t\tSELECT 22, 'Nome falso', 200::DECIMAL INTO retorno;\n\t\tRETURN retorno;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT id, salario FROM cria_instrutor_falso();\n```\n\n***Retorna a consulta do select em si***\n\n```sql\nDROP FUNCTION instrutores_bem_pagos;\n\nCREATE FUNCTION instrutores_bem_pagos(valor_salario DECIMAL)\nRETURNS SETOF instrutor AS $$\n\tBEGIN\n\t\tRETURN QUERY SELECT * FROM instrutor WHERE salario \u003e valor_salario;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT * FROM instrutores_bem_pagos(300);\n```\n\nQual o propósito ou funcionalidade da instrução SELECT INTO?\n\n    SELECT INTO atribui o resultado de uma query a uma variável.\n\nPara saber mais: [Sintaxe](https://www.postgresql.org/docs/current/plpgsql-statements.html#PLPGSQL-STATEMENTS-SQL-ONEROW)\n\n### **If - Else**\n\nA consulta abaixo é mais rápida que a posterior, pois vai direto ao ponto. Com apenas uma consulta, chega ao mesmo resultado. Utiliza uma condição para retornar os registros.\n\n```sql\nCREATE FUNCTION salario_ok(instrutor instrutor)\nRETURNS VARCHAR AS $$\n\tBEGIN\n\t\t-- Se o salário do instrutor for maior do que 200, ok\n\t\tIF instrutor.salario \u003e 200 THEN\n\t\t\tRETURN 'Salário está ok';\n\t\t-- Senão, pode aumentar\n\t\tELSE\n\t\t\tRETURN 'Salário pode aumentar';\n\t\tEND IF;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT nome, salario_ok(instrutor) FROM instrutor;\n```\n\nA query abaixo entrega o mesmo resultado, porém com perda de performance, pois executa mais de uma consulta na mesma função. Existe uma condição e uma consulta extra pelo id.\n\n```sql\nDROP FUNCTION salario_ok;\n\nCREATE FUNCTION salario_ok(id_instrutor INTEGER)\nRETURNS VARCHAR AS $$\n\tDECLARE\n\t\tinstrutor instrutor;\n\tBEGIN\n\t\tSELECT * FROM instrutor WHERE id = id_instrutor INTO instrutor;\n\t\t\n\t\t-- Se o salário do instrutor for maior do que 200, ok\n\t\tIF instrutor.salario \u003e 200 THEN\n\t\t\tRETURN 'Salário está ok';\n\t\t-- Senão, pode aumentar\n\t\tELSE\n\t\t\tRETURN 'Salário pode aumentar';\n\t\tEND IF;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT nome, salario_ok(instrutor.id) FROM instrutor;\n```\n\n### **Elseif**\n\nNo caso de várias condições, pode-se utilizar o `ELSEIF` para reduzir e deixar o código mais legível.\n\n```sql\nCREATE OR REPLACE FUNCTION salario_ok(id_instrutor INTEGER)\nRETURNS VARCHAR AS $$\n\tDECLARE\n\t\tinstrutor instrutor;\n\tBEGIN\n\t\tSELECT * FROM instrutor WHERE id = id_instrutor INTO instrutor;\n\t\t\n\t\t-- Se o salário do instrutor for maior do que 300, ok\n\t\tIF instrutor.salario \u003e 300 THEN\n\t\t\tRETURN 'Salário está ok';\n\t\t\t-- Se forem exatos 300 reais, pode aumentar\n\t\tELSEIF instrutor.salario = 300 THEN\n\t\t\tRETURN 'Salário pode aumentar';\n\t\t\t-- Caso contrário, o salário está defasado\n\t\tELSE\n\t\t\tRETURN 'Salário está defasado';\n\t\tEND IF;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT nome, salario_ok(instrutor.id) FROM instrutor;\n```\n\nObs. Um bloco `IF` não precisa ter nem um bloco `ELSE` nem um bloco `ELSEIF`. Ambos são opcionais.\n\n\u003e Um bloco IF não precisa necessariamente ser acompanhado por ELSE ou ELSEIF. Inclusive é bastante comum na programação termos somente o IF. [Aqui](https://www.postgresql.org/docs/current/plpgsql-control-structures.html#PLPGSQL-CONDITIONALS) você pode conferir a sintaxe.\n\n### **Case When**\n\nO `CASE` funciona semelhante ao `IF`, contudo é ainda mais legível.\n\n```sql\nCREATE OR REPLACE FUNCTION salario_ok(id_instrutor INTEGER)\nRETURNS VARCHAR AS $$\n\tDECLARE\n\t\tinstrutor instrutor;\n\tBEGIN\n\t\tSELECT * FROM instrutor WHERE id = id_instrutor INTO instrutor;\n\t\t\n\t\tCASE\n\t\t\tWHEN instrutor.salario = 100 THEN\n\t\t\t\tRETURN 'Salário muito baixo';\n\t\t\tWHEN instrutor.salario = 200 THEN\n\t\t\t\tRETURN 'Salário baixo';\n\t\t\tWHEN instrutor.salario = 300 THEN\n\t\t\t\tRETURN 'Salário ok';\n\t\t\tELSE\n\t\t\t\tRETURN 'Salário ótimo';\n\t\tEND CASE;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT nome, salario_ok(instrutor.id) FROM instrutor;\n```\n\nPara simplificar o case, pode-se utilizar a expressão de comparação ao case e diferenciar o when.\n\n```sql\nCREATE OR REPLACE FUNCTION salario_ok(id_instrutor INTEGER)\nRETURNS VARCHAR AS $$\n\tDECLARE\n\t\tinstrutor instrutor;\n\tBEGIN\n\t\tSELECT * FROM instrutor WHERE id = id_instrutor INTO instrutor;\n\t\t\n\t\tCASE instrutor.salario\n\t\t\tWHEN 100 THEN\n\t\t\t\tRETURN 'Salário muito baixo';\n\t\t\tWHEN 200 THEN\n\t\t\t\tRETURN 'Salário baixo';\n\t\t\tWHEN 300 THEN\n\t\t\t\tRETURN 'Salário ok';\n\t\t\tELSE\n\t\t\t\tRETURN 'Salário ótimo';\n\t\tEND CASE;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT nome, salario_ok(instrutor.id) FROM instrutor;\n```\n\nQuando parece ser mais interessante usar CASE?\n\n\tQuando precisaríamos de muitos ELSEIFs\n\n\u003e Se nós precisarmos de muito blocos ELSEIF, normalmente podemos trocar por um CASE. Se a comparação for de igualdade, usamos o CASE simples. Senão, podemos usar o Searched case. Dá uma olhada [aqui](https://www.postgresql.org/docs/current/plpgsql-control-structures.html#id-1.8.8.8.6.6) pra mais detalhes.\n\n## 5. Estruturas de repetição\n\n### **Return Next**\n\nO `RETURN NEXT` é utilizado para retornar múltiplas linhas de uma função.\n\n```sql\nCREATE OR REPLACE FUNCTION tabuada(numero INTEGER)\nRETURNS SETOF VARCHAR AS $$\n\tBEGIN\n\t\tRETURN NEXT numero * 1;\n\t\tRETURN NEXT numero * 2;\n\t\tRETURN NEXT numero * 3;\n\t\tRETURN NEXT numero * 4;\n\t\tRETURN NEXT numero * 5;\n\t\tRETURN NEXT numero * 6;\n\t\tRETURN NEXT numero * 7;\n\t\tRETURN NEXT numero * 8;\n\t\tRETURN NEXT numero * 9;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT tabuada(2);\n```\n\nPara saber mais: [SETOF PLpgSQL](https://www.postgresql.org/docs/current/plpgsql-control-structures.html#PLPGSQL-STATEMENTS-RETURNING)\n\n### **Conhecendo Loop**\n\nCriar um `LOOP` faz com que reduza a repetição e o código fique mais legível.\n\n```sql\nDROP FUNCTION tabuada;\n\nCREATE OR REPLACE FUNCTION tabuada(numero INTEGER)\nRETURNS SETOF INTEGER AS $$\n\tDECLARE\n\t\t-- multiplicador que começa com 1 e vai até 10\n\t\tmultiplicador INTEGER DEFAULT 1;\n\tBEGIN\n\t\tLOOP\n\t\t\t-- multiplica numeros\n\t\t\tRETURN NEXT numero * multiplicador;\n\n\t\t\t-- aumenta o multiplicador\n\t\t\tmultiplicador := multiplicador + 1;\n\n\t\t\t-- finaliza o multiplicador\n\t\t\tEXIT WHEN multiplicador = 10;\n\t\tEND LOOP;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT tabuada(3);\n```\n\nPode-se ainda concatenar strings para mostrar o cálculo, não apenas o resultado dele.\n\n```sql\nDROP FUNCTION tabuada;\n\nCREATE OR REPLACE FUNCTION tabuada(numero INTEGER)\nRETURNS SETOF VARCHAR AS $$\n\tDECLARE\n\t\tmultiplicador INTEGER DEFAULT 1;\n\tBEGIN\n\t\tLOOP\n\t\t\tRETURN NEXT numero || ' x ' || multiplicador || ' = ' || numero * multiplicador;\n\t\t\tmultiplicador := multiplicador + 1;\n\t\t\tEXIT WHEN multiplicador = 10;\n\t\tEND LOOP;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT tabuada(4);\n```\n\n### **While**\n\nO `WHILE` funciona como um contador, finalizando o loop quando alcança o que foi definido no while.\n\n```sql\nDROP FUNCTION tabuada;\n\nCREATE OR REPLACE FUNCTION tabuada(numero INTEGER)\nRETURNS SETOF VARCHAR AS $$\n\tDECLARE\n\t\tmultiplicador INTEGER DEFAULT 1;\n\tBEGIN\n\t\tWHILE multiplicador \u003c 10 LOOP\n\t\t\tRETURN NEXT numero || ' x ' || multiplicador || ' = ' || numero * multiplicador;\n\t\t\tmultiplicador := multiplicador + 1;\n\t\tEND LOOP;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT tabuada(5);\n```\n\nQual a principal diferença entre estes LOOP e WHILE … LOOP?\n\n\tSem o WHILE nós precisamos utilizar o EXIT para informar a condição de saída dentro do loop.\n\n\u003e O WHILE já nos permite definir explicitamente a condição de saída. Sem o WHILE nós precisamos, dentro do loop, executar a instrução EXIT para verificar a condição de saída.\n\n### **Conhecendo For**\n\nO `FOR` assim como o while, funciona como um contador, porém ele também faz o incremento do loop. Fazendo com que não seja mais necessário incrementar o loop de 1 em 1 e, também, não mais necessário declarar a variável.\n\n```sql\nDROP FUNCTION tabuada;\n\nCREATE OR REPLACE FUNCTION tabuada(numero INTEGER)\nRETURNS SETOF VARCHAR AS $$\n\tBEGIN\n\t\tFOR multiplicador IN 1..9 LOOP\n\t\t\tRETURN NEXT numero || ' x ' || multiplicador || ' = ' || numero * multiplicador;\n\t\tEND LOOP;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT tabuada(6);\n```\n\nCom o for é possível realizar um loop, inclusive, com uma query.\n\n```sql\nCREATE FUNCTION instrutor_com_salario(\n\tOUT nome VARCHAR,\n\tOUT salario_ok VARCHAR\n)\nRETURNS SETOF record AS $$\n\tDECLARE\n\t\tinstrutor instrutor;\n\tBEGIN\n\t\tFOR instrutor IN SELECT * FROM instrutor LOOP\n\t\t\tnome := instrutor.nome;\n\t\t\tsalario_ok = salario_ok(instrutor.id);\n\t\t\t\n\t\t\tRETURN NEXT;\n\t\tEND LOOP;\n\tEND\n$$ LANGUAGE plpgsql;\n\nSELECT * FROM instrutor_com_salario();\n```\n\n\u003e Estruturas de repetição (do inglês, loops) são muito utilizadas na programação para percorrer listas de valores.\n\u003e Sejam vetores de informações, registros de tabelas, sequências pré-definidas… Em cada caso vamos analisar qual a estrutura ideal de repetição para aplicar.\n\nPara saber mais: [Loops](https://www.postgresql.org/docs/current/plpgsql-control-structures.html#PLPGSQL-CONTROL-STRUCTURES-LOOPS)\n\n## 6. Mão na massa\n\n### **Curso na categoria**\n\nÉ possível criar funções para popular tabelas, inserindo novos registros ou atualizando os existentes. Para isso, é necessário relacionar a função à uma ou mais tabelas e declarar variáveis e campos. Podendo realizar uma verificação se o item já existe antes de realmente inserir como novo.\n\n```sql\nCREATE FUNCTION cria_curso(nome_curso VARCHAR, nome_categoria VARCHAR)\nRETURNS void AS $$\n\tDECLARE\n\t\tid_categoria INTEGER;\n\tBEGIN\n\t\tSELECT id INTO id_categoria FROM categoria\n\t\tWHERE nome = nome_categoria;\n\t\t\n\t\tIF NOT FOUND THEN\n\t\t\tINSERT INTO categoria (nome) VALUES (nome_categoria)\n\t\t\tRETURNING id INTO id_categoria;\n\t\tEND IF;\n\t\t\n\t\tINSERT INTO curso (nome, categoria_id)\n\t\tVALUES (nome_curso, id_categoria);\n\tEND;\n$$ LANGUAGE plpgsql;\n\nSELECT cria_curso('PHP', 'Programação');\nSELECT cria_curso('Java', 'Programação');\n\nSELECT * FROM curso;\nSELECT * FROM categoria;\n```\n\nO que é essa variável FOUND?\n\n\tUma variável que informa se houve algum resultado produzido pela última query executada.\n\n\u003e Esta variável é definida automaticamente em toda função em PLpgSQL e começa como FALSE. Nesse [link](https://www.postgresql.org/docs/current/plpgsql-statements.html#PLPGSQL-STATEMENTS-DIAGNOSTICS) você confere em que situações ela será definida como TRUE.\n\nPara saber mais: [Execute](Para%20saber%20mais/Aula%206%20-%20Atividade%204%20Para%20saber%20mais_%20Execute.pdf)\n\n⬆️ [Voltar ao topo](#postgresql-desenvolva-com-plpgsql) ⬆️\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreadcsousa%2Falura_postgresql-plpgsql_sql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandreadcsousa%2Falura_postgresql-plpgsql_sql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandreadcsousa%2Falura_postgresql-plpgsql_sql/lists"}