{"id":1775,"date":"2026-07-24T18:02:11","date_gmt":"2026-07-24T21:02:11","guid":{"rendered":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/"},"modified":"2026-07-24T18:02:11","modified_gmt":"2026-07-24T21:02:11","slug":"aula-17-functions-funcoes-customizadas-no-mysql","status":"publish","type":"post","link":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/","title":{"rendered":"Aula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL"},"content":{"rendered":"<p>Na engenharia de dados, a capacidade de encapsular l\u00f3gica de neg\u00f3cio reutiliz\u00e1vel diretamente no banco de dados \u00e9 um diferencial competitivo que separa ambientes maduros de implementa\u00e7\u00f5es amadoras. As <strong>functions<\/strong> (fun\u00e7\u00f5es customizadas) no MySQL representam exatamente essa capacidade: rotinas armazenadas que recebem par\u00e2metros, executam processamento interno e retornam um \u00fanico valor escalar \u2014 seja para compor uma cl\u00e1usula <strong>SELECT<\/strong>, integrar-se a um <strong>WHERE<\/strong> ou at\u00e9 mesmo alimentar uma trigger. Diferentemente das <strong>stored procedures<\/strong>, que estudamos na aula anterior, as <strong>functions<\/strong> s\u00e3o projetadas para serem invocadas como parte de express\u00f5es SQL, o que as torna ideais para c\u00e1lculos, formata\u00e7\u00f5es, valida\u00e7\u00f5es e transforma\u00e7\u00f5es de dados que precisam ser executadas com consist\u00eancia em todo o ecossistema da aplica\u00e7\u00e3o.<\/p>\n<p>Por que isso importa tanto no dia a dia de um profissional de TI ou DBA? Imagine um cen\u00e1rio onde dez aplica\u00e7\u00f5es diferentes consultam a mesma base de dados e todas precisam calcular o mesmo indicador financeiro, como o valor presente l\u00edquido de um contrato ou a idade exata de um cliente com base na data de nascimento. Sem <strong>functions<\/strong>, cada equipe implementaria essa l\u00f3gica em sua pr\u00f3pria camada de aplica\u00e7\u00e3o \u2014 em Python, Java, PHP, Node.js \u2014 introduzindo o risco real de diverg\u00eancias de resultado por diferen\u00e7as de arredondamento, interpreta\u00e7\u00e3o de regras de neg\u00f3cio ou simples erro humano. Com uma <strong>function<\/strong> armazenada no MySQL, a l\u00f3gica \u00e9 escrita uma \u00fanica vez, validada exaustivamente e consumida por todas as aplica\u00e7\u00f5es exatamente da mesma forma. Na JRT Technology Solutions, implementamos dezenas de fun\u00e7\u00f5es customizadas em ambientes cr\u00edticos de nossos clientes justamente para eliminar esse tipo de inconsist\u00eancia e centralizar a governan\u00e7a dos dados.<\/p>\n<p>Nesta aula, voc\u00ea transcender\u00e1 o uso b\u00e1sico de fun\u00e7\u00f5es nativas como <strong>NOW()<\/strong>, <strong>CONCAT()<\/strong> ou <strong>DATEDIFF()<\/strong> e passar\u00e1 a criar suas pr\u00f3prias <strong>functions<\/strong> com a sintaxe <strong>CREATE FUNCTION<\/strong>. Abordaremos desde a estrutura fundamental da declara\u00e7\u00e3o \u2014 incluindo a cl\u00e1usula <strong>RETURNS<\/strong>, os modificadores <strong>DETERMINISTIC<\/strong> e <strong>NOT DETERMINISTIC<\/strong>, e o corpo com <strong>BEGIN&#8230;END<\/strong> \u2014 at\u00e9 t\u00f3picos avan\u00e7ados como tratamento de exce\u00e7\u00f5es com <strong>DECLARE HANDLER<\/strong>, vari\u00e1veis locais, cursores dentro de fun\u00e7\u00f5es e as implica\u00e7\u00f5es de seguran\u00e7a relacionadas ao <strong>log_bin_trust_function_creators<\/strong>. Tudo com exemplos reais que voc\u00ea poder\u00e1 executar imediatamente no seu ambiente de testes.<\/p>\n<p>Ao final desta aula, voc\u00ea ter\u00e1 plena capacidade de projetar, codificar, depurar e implantar fun\u00e7\u00f5es customizadas em produ\u00e7\u00e3o, compreendendo n\u00e3o apenas o &#8220;como&#8221; sint\u00e1tico, mas tamb\u00e9m o &#8220;quando&#8221; e o &#8220;porqu\u00ea&#8221; estrat\u00e9gico de utiliz\u00e1-las. Se voc\u00ea acompanhou as aulas anteriores com dedica\u00e7\u00e3o, especialmente a Aula 15 sobre <strong>Stored Procedures<\/strong> e a Aula 12 sobre <strong>Vari\u00e1veis e Estruturas de Controle<\/strong>, perceber\u00e1 que esta aula funciona como a pe\u00e7a que faltava para completar seu dom\u00ednio sobre a programa\u00e7\u00e3o server-side no MySQL. Vamos colocar a m\u00e3o no c\u00f3digo.<\/p>\n<h3>O que voc\u00ea vai aprender nesta aula<\/h3>\n<ul>\n<li>Compreender o conceito de <strong>stored functions<\/strong> e diferenci\u00e1-las das <strong>stored procedures<\/strong> em prop\u00f3sito, sintaxe e uso<\/li>\n<li>Dominar a sintaxe completa do comando <strong>CREATE FUNCTION<\/strong>, incluindo cada cl\u00e1usula obrigat\u00f3ria e opcional<\/li>\n<li>Trabalhar com os modificadores <strong>DETERMINISTIC<\/strong>, <strong>NOT DETERMINISTIC<\/strong>, <strong>CONTAINS SQL<\/strong>, <strong>READS SQL DATA<\/strong> e <strong>MODIFIES SQL DATA<\/strong><\/li>\n<li>Declarar vari\u00e1veis locais com <strong>DECLARE<\/strong>, utilizar estruturas condicionais (<strong>IF&#8230;THEN&#8230;ELSE<\/strong>) e la\u00e7os (<strong>WHILE<\/strong>, <strong>REPEAT<\/strong>) dentro de fun\u00e7\u00f5es<\/li>\n<li>Tratar erros e exce\u00e7\u00f5es com <strong>DECLARE HANDLER<\/strong> para garantir robustez em produ\u00e7\u00e3o<\/li>\n<li>Implementar fun\u00e7\u00f5es pr\u00e1ticas: c\u00e1lculo de idade, formata\u00e7\u00e3o de documentos, valida\u00e7\u00e3o de dados e transforma\u00e7\u00e3o de strings<\/li>\n<li>Diagnosticar e corrigir os erros mais frequentes ao criar e executar functions no MySQL<\/li>\n<li>Aplicar boas pr\u00e1ticas de nomenclatura, documenta\u00e7\u00e3o e versionamento de fun\u00e7\u00f5es em ambientes corporativos<\/li>\n<\/ul>\n<h3>Pr\u00e9-requisitos e Ambiente<\/h3>\n<p>Para acompanhar esta aula com aproveitamento m\u00e1ximo, voc\u00ea precisar\u00e1 de um servidor MySQL na vers\u00e3o <strong>8.0<\/strong> ou superior em execu\u00e7\u00e3o \u2014 embora a maioria dos conceitos se aplique tamb\u00e9m ao MySQL 5.7, utilizaremos recursos espec\u00edficos da vers\u00e3o 8 que facilitam o desenvolvimento, como a melhoria na detec\u00e7\u00e3o de erros sint\u00e1ticos e o suporte aprimorado a <strong>CTEs<\/strong> que podem ser combinadas com fun\u00e7\u00f5es. O ambiente pode ser Linux (Ubuntu 22.04\/24.04 LTS, Rocky Linux 9, CentOS Stream 9) ou Windows 10\/11 com MySQL instalado via instalador oficial ou <strong>MySQL Installer<\/strong>. Voc\u00ea precisar\u00e1 de privil\u00e9gios de <strong>CREATE ROUTINE<\/strong> e <strong>EXECUTE<\/strong> no banco de dados onde trabalhar\u00e1 \u2014 se estiver utilizando o usu\u00e1rio <strong>root<\/strong> ou um usu\u00e1rio com grant <strong>ALL PRIVILEGES<\/strong>, estar\u00e1 adequadamente configurado. Recomendamos tamb\u00e9m ter uma ferramenta cliente como <strong>MySQL Workbench<\/strong>, <strong>DBeaver<\/strong> ou o pr\u00f3prio <strong>mysql<\/strong> CLI, pois escrever fun\u00e7\u00f5es diretamente no terminal exige aten\u00e7\u00e3o extra com delimitadores.<\/p>\n<p>Como esta \u00e9 uma aula de n\u00edvel intermedi\u00e1rio, assumimos que voc\u00ea j\u00e1 concluiu as aulas anteriores do curso e est\u00e1 familiarizado com: cria\u00e7\u00e3o de bancos de dados e tabelas (<strong>CREATE DATABASE<\/strong>, <strong>CREATE TABLE<\/strong>), tipos de dados do MySQL (<strong>INT<\/strong>, <strong>VARCHAR<\/strong>, <strong>DATE<\/strong>, <strong>DECIMAL<\/strong>), comandos b\u00e1sicos de manipula\u00e7\u00e3o (<strong>INSERT<\/strong>, <strong>UPDATE<\/strong>, <strong>DELETE<\/strong>, <strong>SELECT<\/strong>), conceito de <strong>stored procedures<\/strong> (Aula 15) e fundamentos de vari\u00e1veis e estruturas de controle (Aula 12). Se algum desses t\u00f3picos ainda n\u00e3o estiver consolidado, sugerimos revisitar as aulas correspondentes antes de prosseguir \u2014 a curva de aprendizado aqui ser\u00e1 significativamente mais suave com esses pr\u00e9-requisitos bem assentados. Prepare seu ambiente, abra seu cliente SQL favorito e conecte-se ao servidor. Vamos come\u00e7ar criando um banco de dados de trabalho espec\u00edfico para esta aula.<\/p>\n<pre><code>-- Conecte-se ao MySQL com privil\u00e9gios administrativos\nmysql -u root -p\n\n-- Crie o banco de dados para a aula\nCREATE DATABASE IF NOT EXISTS aula_functions CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\n\n-- Selecione o banco de dados\nUSE aula_functions;\n\n-- Verifique a vers\u00e3o do servidor para confirmar compatibilidade\nSELECT VERSION();<\/code><\/pre>\n<pre><code class=\"output\">mysql&gt; CREATE DATABASE IF NOT EXISTS aula_functions CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\nQuery OK, 1 row affected (0.01 sec)\n\nmysql&gt; USE aula_functions;\nDatabase changed\n\nmysql&gt; SELECT VERSION();\n+-----------+\n| VERSION() |\n+-----------+\n| 8.0.36    |\n+-----------+\n1 row in set (0.00 sec)<\/code><\/pre>\n<h3>Conceito Fundamental: O que s\u00e3o Functions e como diferem de Stored Procedures<\/h3>\n<p>Uma <strong>function<\/strong> (fun\u00e7\u00e3o armazenada ou stored function) \u00e9 um objeto de schema que encapsula um bloco de c\u00f3digo SQL com a finalidade expl\u00edcita de <strong>retornar um \u00fanico valor<\/strong> ao chamador. Diferentemente das <strong>stored procedures<\/strong> \u2014 que podem retornar m\u00faltiplos resultsets, modificar dados, gerenciar transa\u00e7\u00f5es e at\u00e9 mesmo n\u00e3o retornar nada \u2014 as <strong>functions<\/strong> possuem um contrato mais restrito e, justamente por isso, podem ser utilizadas em contextos onde procedures n\u00e3o s\u00e3o permitidas: dentro de uma cl\u00e1usula <strong>SELECT<\/strong>, como parte de uma express\u00e3o em <strong>WHERE<\/strong>, na defini\u00e7\u00e3o de uma coluna virtual ou at\u00e9 mesmo como valor default de um campo. Essa versatilidade posicional \u00e9 o que torna as fun\u00e7\u00f5es t\u00e3o poderosas: voc\u00ea pode escrever <strong>SELECT nome, calcular_idade(data_nascimento) FROM clientes<\/strong> e obter o resultado como se <strong>calcular_idade()<\/strong> fosse uma fun\u00e7\u00e3o nativa do MySQL.<\/p>\n<p>Para ilustrar a diferen\u00e7a com um exemplo concreto: se voc\u00ea precisa registrar um log de auditoria sempre que um sal\u00e1rio for atualizado, uma <strong>procedure<\/strong> \u00e9 a escolha natural, pois ela pode executar o <strong>UPDATE<\/strong> e em seguida um <strong>INSERT<\/strong> na tabela de log, sem retornar valor algum. Por outro lado, se voc\u00ea precisa calcular o valor do imposto de renda com base em uma faixa salarial e usar esse valor em diversas queries de relat\u00f3rios diferentes, uma <strong>function<\/strong> \u00e9 o instrumento correto \u2014 ela receber\u00e1 o sal\u00e1rio como par\u00e2metro, processar\u00e1 as al\u00edquotas progressivas e retornar\u00e1 o imposto calculado, podendo ser invocada em qualquer <strong>SELECT<\/strong> como parte da proje\u00e7\u00e3o de colunas. Na JRT Technology Solutions, orientamos nossos clientes a adotarem <strong>functions<\/strong> para l\u00f3gicas de c\u00e1lculo determin\u00edstico que precisam ser consumidas por m\u00faltiplas aplica\u00e7\u00f5es, enquanto reservamos <strong>procedures<\/strong> para opera\u00e7\u00f5es transacionais complexas que envolvem m\u00faltiplas etapas e podem ou n\u00e3o retornar dados.<\/p>\n<p>Outra diferen\u00e7a crucial est\u00e1 no tratamento de par\u00e2metros: <strong>functions<\/strong> aceitam apenas par\u00e2metros de entrada (<strong>IN<\/strong> impl\u00edcito \u2014 voc\u00ea n\u00e3o especifica a dire\u00e7\u00e3o, pois todos os par\u00e2metros s\u00e3o de entrada), enquanto <strong>procedures<\/strong> suportam par\u00e2metros <strong>IN<\/strong>, <strong>OUT<\/strong> e <strong>INOUT<\/strong>. Isso refor\u00e7a o paradigma funcional: a fun\u00e7\u00e3o recebe insumos, processa e devolve um resultado, sem efeitos colaterais nos argumentos recebidos. Essa pureza conceitual, embora n\u00e3o estritamente aplicada pelo MySQL (que permite que uma fun\u00e7\u00e3o modifique dados, desde que declarada com <strong>MODIFIES SQL DATA<\/strong>), deve ser perseguida como boa pr\u00e1tica: fun\u00e7\u00f5es que alteram estado do banco s\u00e3o consideradas m\u00e1s pr\u00e1ticas e podem gerar comportamentos inesperados quando executadas dentro de queries maiores.<\/p>\n<p>A tabela a seguir sintetiza as diferen\u00e7as fundamentais que voc\u00ea deve ter em mente ao decidir entre uma function e uma procedure:<\/p>\n<table border=\"1\" cellpadding=\"8\" cellspacing=\"0\" style=\"border-collapse: collapse; width: 100%;\">\n<thead>\n<tr style=\"background-color: #f0f0f0;\">\n<th>Caracter\u00edstica<\/th>\n<th>Function<\/th>\n<th>Stored Procedure<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>Prop\u00f3sito principal<\/strong><\/td>\n<td>Retornar um valor escalar<\/td>\n<td>Executar um conjunto de opera\u00e7\u00f5es<\/td>\n<\/tr>\n<tr>\n<td><strong>Uso em SELECT<\/strong><\/td>\n<td>Sim \u2014 como express\u00e3o<\/td>\n<td>N\u00e3o \u2014 requer CALL<\/td>\n<\/tr>\n<tr>\n<td><strong>Par\u00e2metros OUT\/INOUT<\/strong><\/td>\n<td>N\u00e3o suportados<\/td>\n<td>Suportados<\/td>\n<\/tr>\n<tr>\n<td><strong>Retorno m\u00faltiplo<\/strong><\/td>\n<td>N\u00e3o \u2014 apenas um valor<\/td>\n<td>Sim \u2014 m\u00faltiplos resultsets<\/td>\n<\/tr>\n<tr>\n<td><strong>Transa\u00e7\u00f5es internas<\/strong><\/td>\n<td>N\u00e3o recomendado<\/td>\n<td>Sim \u2014 COMMIT\/ROLLBACK<\/td>\n<\/tr>\n<tr>\n<td><strong>Chamada<\/strong><\/td>\n<td>Como parte de express\u00e3o SQL<\/td>\n<td><strong>CALL nome_procedure()<\/strong><\/td>\n<\/tr>\n<tr>\n<td><strong>Modificador SQL<\/strong><\/td>\n<td>Obrigat\u00f3rio (DETERMINISTIC, etc.)<\/td>\n<td>Opcional<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Sintaxe Completa do CREATE FUNCTION<\/h3>\n<p>O comando <strong>CREATE FUNCTION<\/strong> segue uma estrutura bem definida que voc\u00ea precisa memorizar, pois qualquer desvio resultar\u00e1 em erro sint\u00e1tico. A forma geral \u00e9 a seguinte \u2014 e recomendo que voc\u00ea a mantenha \u00e0 m\u00e3o como refer\u00eancia r\u00e1pida durante seus desenvolvimentos:<\/p>\n<pre><code>CREATE\n    [DEFINER = usuario]\n    FUNCTION nome_da_funcao (param1 TIPO, param2 TIPO, ...)\n    RETURNS TIPO_DE_RETORNO\n    [DETERMINISTIC | NOT DETERMINISTIC]\n    [CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA]\n    [SQL SECURITY {DEFINER | INVOKER}]\n    [COMMENT 'descricao da funcao']\n    corpo_da_funcao<\/code><\/pre>\n<p>Vamos detalhar cada componente dessa estrutura para que voc\u00ea compreenda n\u00e3o apenas a sintaxe, mas a sem\u00e2ntica por tr\u00e1s de cada cl\u00e1usula. O <strong>DEFINER<\/strong> (opcional) especifica qual usu\u00e1rio ser\u00e1 considerado o &#8220;dono&#8221; da fun\u00e7\u00e3o para fins de verifica\u00e7\u00e3o de privil\u00e9gios \u2014 se omitido, o usu\u00e1rio que executa o <strong>CREATE FUNCTION<\/strong> torna-se o definer. O <strong>nome_da_funcao<\/strong> deve ser \u00fanico dentro do banco de dados (schema) e seguir as regras de identificadores do MySQL: at\u00e9 64 caracteres, podendo conter letras, n\u00fameros, underscore e cifr\u00e3o. Os <strong>par\u00e2metros<\/strong> s\u00e3o declarados com nome e tipo, separados por v\u00edrgulas \u2014 todos s\u00e3o implicitamente de entrada. A cl\u00e1usula <strong>RETURNS<\/strong> (com S no final \u2014 cuidado para n\u00e3o escrever <strong>RETURN<\/strong>) define o tipo de dado que a fun\u00e7\u00e3o devolver\u00e1: pode ser qualquer tipo v\u00e1lido do MySQL, incluindo <strong>INT<\/strong>, <strong>VARCHAR(n)<\/strong>, <strong>DECIMAL(p,s)<\/strong>, <strong>DATE<\/strong>, <strong>DATETIME<\/strong>, <strong>TEXT<\/strong> e at\u00e9 mesmo <strong>JSON<\/strong>.<\/p>\n<p>Os modificadores <strong>DETERMINISTIC<\/strong> e <strong>NOT DETERMINISTIC<\/strong> informam ao otimizador do MySQL se a fun\u00e7\u00e3o sempre retorna o mesmo resultado para os mesmos par\u00e2metros de entrada. Uma fun\u00e7\u00e3o determin\u00edstica \u2014 como <strong>calcular_dobro(x)<\/strong> que retorna <strong>x * 2<\/strong> \u2014 permite que o MySQL otimize chamadas repetidas dentro de uma mesma query, armazenando em cache o resultado e reutilizando-o. J\u00e1 fun\u00e7\u00f5es n\u00e3o determin\u00edsticas \u2014 como uma que retorna <strong>NOW()<\/strong> ou consulta uma tabela cujo conte\u00fado muda frequentemente \u2014 devem ser declaradas com <strong>NOT DETERMINISTIC<\/strong>. A escolha correta afeta diretamente a performance de queries complexas e a replica\u00e7\u00e3o bin\u00e1ria. Em nossos projetos na JRT Technology Solutions, sempre auditamos as fun\u00e7\u00f5es de produ\u00e7\u00e3o para garantir que a flag de determinismo esteja corretamente configurada, pois j\u00e1 presenciamos cen\u00e1rios onde uma fun\u00e7\u00e3o marcada como <strong>DETERMINISTIC<\/strong> mas que na pr\u00e1tica acessava dados vari\u00e1veis causou inconsist\u00eancias em replica\u00e7\u00e3o.<\/p>\n<p>As cl\u00e1usulas <strong>CONTAINS SQL<\/strong>, <strong>NO SQL<\/strong>, <strong>READS SQL DATA<\/strong> e <strong>MODIFIES SQL DATA<\/strong> s\u00e3o obrigat\u00f3rias em algumas configura\u00e7\u00f5es de seguran\u00e7a e servem como documenta\u00e7\u00e3o do comportamento da fun\u00e7\u00e3o. <strong>CONTAINS SQL<\/strong> indica que a fun\u00e7\u00e3o executa comandos SQL sem ler ou modificar dados (por exemplo, apenas manipula vari\u00e1veis com <strong>SET<\/strong>). <strong>NO SQL<\/strong> declara que a fun\u00e7\u00e3o n\u00e3o executa SQL algum. <strong>READS SQL DATA<\/strong> permite leitura de tabelas (<strong>SELECT<\/strong>). <strong>MODIFIES SQL DATA<\/strong> autoriza opera\u00e7\u00f5es de escrita (<strong>INSERT<\/strong>, <strong>UPDATE<\/strong>, <strong>DELETE<\/strong>) \u2014 que, como mencionamos, devem ser evitadas em fun\u00e7\u00f5es sempre que poss\u00edvel. O <strong>SQL SECURITY<\/strong> define se a fun\u00e7\u00e3o ser\u00e1 executada com os privil\u00e9gios do <strong>DEFINER<\/strong> (comportamento padr\u00e3o) ou do <strong>INVOKER<\/strong> (usu\u00e1rio que chamou a fun\u00e7\u00e3o) \u2014 um controle important\u00edssimo em ambientes multi-tenant.<\/p>\n<h3>Criando sua Primeira Function: Calculadora de Idade<\/h3>\n<p>Nada melhor do que um exemplo pr\u00e1tico completo para fixar a teoria. Vamos criar uma fun\u00e7\u00e3o chamada <strong>calcular_idade<\/strong> que recebe uma data de nascimento (<strong>DATE<\/strong>) e retorna a idade em anos como um <strong>INT<\/strong>. Esta \u00e9 uma das fun\u00e7\u00f5es mais solicitadas em ambientes corporativos e servir\u00e1 como ve\u00edculo para demonstrarmos cada aspecto da sintaxe. Antes de criar a fun\u00e7\u00e3o, vamos preparar uma tabela de exemplo para podermos test\u00e1-la em consultas reais:<\/p>\n<pre><code>-- Tabela de clientes para testar a fun\u00e7\u00e3o\nCREATE TABLE clientes (\n    id INT AUTO_INCREMENT PRIMARY KEY,\n    nome VARCHAR(100) NOT NULL,\n    data_nascimento DATE NOT NULL,\n    email VARCHAR(150)\n) ENGINE=InnoDB;\n\n-- Inserindo dados de exemplo\nINSERT INTO clientes (nome, data_nascimento, email) VALUES\n('Ana Silva', '1990-05-14', 'ana.silva@email.com'),\n('Carlos Oliveira', '1985-11-23', 'carlos.oliveira@email.com'),\n('Mariana Santos', '2000-01-07', 'mariana.santos@email.com'),\n('Roberto Almeida', '1978-09-30', 'roberto.almeida@email.com'),\n('Juliana Costa', '1995-03-18', NULL);\n\n-- Verificar os dados inseridos\nSELECT * FROM clientes;<\/code><\/pre>\n<pre><code class=\"output\">+----+------------------+-----------------+---------------------------+\n| id | nome             | data_nascimento | email                     |\n+----+------------------+-----------------+---------------------------+\n|  1 | Ana Silva        | 1990-05-14      | ana.silva@email.com       |\n|  2 | Carlos Oliveira  | 1985-11-23      | carlos.oliveira@email.com |\n|  3 | Mariana Santos   | 2000-01-07      | mariana.santos@email.com  |\n|  4 | Roberto Almeida  | 1978-09-30      | roberto.almeida@email.com |\n|  5 | Juliana Costa    | 1995-03-18      | NULL                      |\n+----+------------------+-----------------+---------------------------+\n5 rows in set (0.00 sec)<\/code><\/pre>\n<p>Agora sim, vamos \u00e0 cria\u00e7\u00e3o da fun\u00e7\u00e3o. Observe atentamente cada linha e o uso do comando <strong>DELIMITER<\/strong> \u2014 essencial para que o MySQL interprete o bloco <strong>BEGIN&#8230;END<\/strong> corretamente sem se confundir com os ponto-e-v\u00edrgulas internos:<\/p>\n<pre><code>-- Alterar o delimitador para evitar conflito com ; dentro do BEGIN...END\nDELIMITER \/\/\n\nCREATE FUNCTION calcular_idade(data_nasc DATE)\nRETURNS INT\nDETERMINISTIC\nREADS SQL DATA\nCOMMENT 'Calcula a idade em anos com base na data de nascimento'\nBEGIN\n    DECLARE idade INT;\n    \n    -- Calcula a diferen\u00e7a em anos considerando m\u00eas e dia atuais\n    SET idade = TIMESTAMPDIFF(YEAR, data_nasc, CURDATE());\n    \n    -- Ajusta se ainda n\u00e3o fez anivers\u00e1rio no ano corrente\n    IF DATE_ADD(data_nasc, INTERVAL idade YEAR) > CURDATE() THEN\n        SET idade = idade - 1;\n    END IF;\n    \n    RETURN idade;\nEND \/\/\n\n-- Restaurar o delimitador padr\u00e3o\nDELIMITER ;<\/code><\/pre>\n<pre><code class=\"output\">Query OK, 0 rows affected (0.02 sec)<\/code><\/pre>\n<p>Vamos dissecar este c\u00f3digo linha por linha, pois h\u00e1 nuances importantes. A instru\u00e7\u00e3o <strong>DELIMITER \/\/<\/strong> redefine temporariamente o caractere que o MySQL interpreta como &#8220;fim de comando&#8221;. Sem essa altera\u00e7\u00e3o, o primeiro <strong>;<\/strong> encontrado dentro do <strong>BEGIN&#8230;END<\/strong> encerraria prematuramente a defini\u00e7\u00e3o da fun\u00e7\u00e3o, gerando um erro de sintaxe. Dentro do corpo, declaramos uma vari\u00e1vel local <strong>idade<\/strong> do tipo <strong>INT<\/strong> usando <strong>DECLARE<\/strong> \u2014 lembre-se de que declara\u00e7\u00f5es de vari\u00e1veis devem vir antes de qualquer outro comando execut\u00e1vel dentro do bloco. A fun\u00e7\u00e3o <strong>TIMESTAMPDIFF(YEAR, data_nasc, CURDATE())<\/strong> retorna a diferen\u00e7a em anos entre as duas datas, mas de forma &#8220;truncada&#8221;: se a pessoa nasceu em 01\/12\/1990 e hoje \u00e9 24\/07\/2026, ela retornar\u00e1 35, pois j\u00e1 passou da data. O ajuste condicional no <strong>IF<\/strong> verifica se somando a idade calculada \u00e0 data de nascimento obtemos uma data futura \u2014 caso positivo, subtra\u00edmos 1 para corrigir o valor. Finalmente, <strong>RETURN idade<\/strong> entrega o valor escalar prometido pela assinatura <strong>RETURNS INT<\/strong>.<\/p>\n<p>Uma vez criada, a fun\u00e7\u00e3o pode ser utilizada imediatamente em qualquer query. Vamos test\u00e1-la contra nossa tabela de clientes para verificar o resultado:<\/p>\n<pre><code>-- Utilizando a fun\u00e7\u00e3o em uma consulta SELECT\nSELECT \n    nome,\n    data_nascimento,\n    calcular_idade(data_nascimento) AS idade_atual\nFROM clientes\nORDER BY idade_atual DESC;\n\n-- Tamb\u00e9m pode ser usada em cl\u00e1usula WHERE\nSELECT nome, data_nascimento\nFROM clientes\nWHERE calcular_idade(data_nascimento) >= 35;<\/code><\/pre>\n<pre><code class=\"output\">+------------------+-----------------+-------------+\n| nome             | data_nascimento | idade_atual |\n+------------------+-----------------+-------------+\n| Roberto Almeida  | 1978-09-30      |          47 |\n| Carlos Oliveira  | 1985-11-23      |          40 |\n| Ana Silva        | 1990-05-14      |          36 |\n| Juliana Costa    | 1995-03-18      |          31 |\n| Mariana Santos   | 2000-01-07      |          26 |\n+------------------+-----------------+-------------+\n5 rows in set (0.00 sec)\n\n+------------------+-----------------+\n| nome             | data_nascimento |\n+------------------+-----------------+\n| Ana Silva        | 1990-05-14      |\n| Carlos Oliveira  | 1985-11-23      |\n| Roberto Almeida  | 1978-09-30      |\n+------------------+-----------------+\n3 rows in set (0.00 sec)<\/code><\/pre>\n<h3>Functions com L\u00f3gica Condicional Complexa: Formatador de CPF<\/h3>\n<p>Elevemos a complexidade com um exemplo do mundo real que utilizamos frequentemente na JRT Technology Solutions para projetos de migra\u00e7\u00e3o e limpeza de dados. Criaremos uma fun\u00e7\u00e3o chamada <strong>formatar_cpf<\/strong> que recebe uma string contendo um CPF (que pode estar em diversos formatos: puro, com pontos e tra\u00e7o, com espa\u00e7os, etc.) e retorna o CPF formatado no padr\u00e3o <strong>XXX.XXX.XXX-XX<\/strong> ou <strong>NULL<\/strong> se o valor fornecido for inv\u00e1lido. Esta fun\u00e7\u00e3o demonstrar\u00e1 manipula\u00e7\u00e3o avan\u00e7ada de strings, uso da fun\u00e7\u00e3o <strong>REGEXP_REPLACE<\/strong> do MySQL 8, valida\u00e7\u00f5es aninhadas com <strong>IF&#8230;THEN&#8230;ELSEIF&#8230;ELSE<\/strong> e a import\u00e2ncia de retornar um valor seguro mesmo diante de entradas inesperadas.<\/p>\n<pre><code>DELIMITER $$\n\nCREATE FUNCTION formatar_cpf(cpf_bruto VARCHAR(20))\nRETURNS VARCHAR(14)\nDETERMINISTIC\nCONTAINS SQL\nCOMMENT 'Formata um CPF removendo caracteres n\u00e3o num\u00e9ricos e aplicando a m\u00e1scara XXX.XXX.XXX-XX'\nBEGIN\n    DECLARE cpf_limpo VARCHAR(11);\n    DECLARE cpf_formatado VARCHAR(14);\n    \n    -- Remove qualquer caractere que n\u00e3o seja d\u00edgito\n    SET cpf_limpo = REGEXP_REPLACE(cpf_bruto, '[^0-9]', '');\n    \n    -- Se a string resultante n\u00e3o tiver exatamente 11 d\u00edgitos, retorna NULL (inv\u00e1lido)\n    IF CHAR_LENGTH(cpf_limpo) != 11 THEN\n        RETURN NULL;\n    END IF;\n    \n    -- Aplica a m\u00e1scara: XXX.XXX.XXX-XX\n    SET cpf_formatado = CONCAT(\n        SUBSTRING(cpf_limpo, 1, 3), '.',\n        SUBSTRING(cpf_limpo, 4, 3), '.',\n        SUBSTRING(cpf_limpo, 7, 3), '-',\n        SUBSTRING(cpf_limpo, 10, 2)\n    );\n    \n    RETURN cpf_formatado;\nEND $$\n\nDELIMITER ;<\/code><\/pre>\n<p>Analisemos as t\u00e9cnicas empregadas neste c\u00f3digo. <strong>REGEXP_REPLACE(cpf_bruto, &#8216;[^0-9]&#8217;, &#8221;)<\/strong> \u00e9 uma fun\u00e7\u00e3o poderosa introduzida no MySQL 8.0 que utiliza express\u00f5es regulares para substitui\u00e7\u00e3o. O padr\u00e3o <strong>&#8216;[^0-9]&#8217;<\/strong> significa &#8220;qualquer caractere que N\u00c3O seja um d\u00edgito de 0 a 9&#8221; \u2014 a nega\u00e7\u00e3o \u00e9 dada pelo circunflexo dentro dos colchetes. Esses caracteres s\u00e3o substitu\u00eddos por string vazia, efetivamente removendo pontos, tra\u00e7os, espa\u00e7os e qualquer outra &#8220;sujeira&#8221; do CPF. O resultado \u00e9 armazenado na vari\u00e1vel <strong>cpf_limpo<\/strong>. Em seguida, a valida\u00e7\u00e3o de comprimento com <strong>CHAR_LENGTH<\/strong> (que conta caracteres, n\u00e3o bytes) garante que entradas como &#8220;123&#8221; ou textos sem sentido retornem <strong>NULL<\/strong> de forma elegante, sem quebrar a query. A formata\u00e7\u00e3o final utiliza <strong>CONCAT<\/strong> e <strong>SUBSTRING<\/strong> para fatiar a string limpa em quatro grupos e intercalar os separadores.<\/p>\n<p>Para testar a robustez da fun\u00e7\u00e3o, vamos submet\u00ea-la a uma variedade de formatos de entrada \u2014 este tipo de teste de estresse \u00e9 exatamente o que fazemos em nossos projetos na JRT Technology Solutions antes de homologar qualquer fun\u00e7\u00e3o para produ\u00e7\u00e3o:<\/p>\n<pre><code>-- Testes com diferentes formatos de entrada\nSELECT \n    formatar_cpf('12345678909') AS caso1_puro,\n    formatar_cpf('123.456.789-09') AS caso2_formatado,\n    formatar_cpf('123 456 789 09') AS caso3_espacos,\n    formatar_cpf('123.456.789\/09') AS caso4_barra,\n    formatar_cpf('abc123def456ghi789jkl09') AS caso5_misturado,\n    formatar_cpf('12345') AS caso6_incompleto,\n    formatar_cpf(NULL) AS caso7_nulo;<\/code><\/pre>\n<pre><code class=\"output\">+-------------+-----------------+----------------+--------------+-----------------+------------------+------------+\n| caso1_puro  | caso2_formatado | caso3_espacos  | caso4_barra  | caso5_misturado | caso6_incompleto | caso7_nulo |\n+-------------+-----------------+----------------+--------------+-----------------+------------------+------------+\n| 123.456.789-09 | 123.456.789-09 | 123.456.789-09 | 123.456.789-09 | 123.456.789-09 | NULL             | NULL       |\n+-------------+-----------------+----------------+--------------+-----------------+------------------+------------+\n1 row in set (0.00 sec)<\/code><\/pre>\n<h3>Trabalhando com Vari\u00e1veis Locais, Cursores e Tratamento de Erros<\/h3>\n<p>Fun\u00e7\u00f5es n\u00e3o precisam se limitar a c\u00e1lculos simples \u2014 elas podem interagir com o banco de dados de forma controlada. Vamos criar uma fun\u00e7\u00e3o mais sofisticada: <strong>obter_status_cliente<\/strong>, que recebe um <strong>id<\/strong> de cliente e retorna uma string descritiva com seu status baseado em regras de neg\u00f3cio que consultam outras tabelas. Para este exemplo, precisaremos de uma tabela adicional de pedidos e demonstraremos o uso de <strong>cursor<\/strong> para iterar sobre m\u00faltiplas linhas, <strong>DECLARE HANDLER<\/strong> para tratamento de exce\u00e7\u00f5es e vari\u00e1veis de controle de fluxo:<\/p>\n<pre><code>-- Cria\u00e7\u00e3o da tabela de pedidos para o exemplo\nCREATE TABLE pedidos (\n    id INT AUTO_INCREMENT PRIMARY KEY,\n    cliente_id INT NOT NULL,\n    data_pedido DATE NOT NULL,\n    valor DECIMAL(10,2) NOT NULL,\n    status ENUM('PENDENTE','APROVADO','ENTREGUE','CANCELADO') NOT NULL,\n    FOREIGN KEY (cliente_id) REFERENCES clientes(id)\n) ENGINE=InnoDB;\n\n-- Inser\u00e7\u00e3o de pedidos de exemplo\nINSERT INTO pedidos (cliente_id, data_pedido, valor, status) VALUES\n(1, '2026-01-15', 1500.00, 'ENTREGUE'),\n(1, '2026-06-20', 2300.00, 'APROVADO'),\n(2, '2025-12-01', 500.00, 'ENTREGUE'),\n(2, '2026-02-10', 1200.00, 'CANCELADO'),\n(3, '2026-07-10', 3200.00, 'PENDENTE'),\n(4, '2026-03-05', 800.00, 'ENTREGUE'),\n(4, '2026-05-18', 1800.00, 'ENTREGUE'),\n(4, '2026-07-01', 950.00, 'APROVADO');\n\n-- Conferir os dados\nSELECT * FROM pedidos;<\/code><\/pre>\n<pre><code class=\"output\">+----+------------+-------------+---------+-----------+\n| id | cliente_id | data_pedido | valor   | status    |\n+----+------------+-------------+---------+-----------+\n|  1 |          1 | 2026-01-15  | 1500.00 | ENTREGUE  |\n|  2 |          1 | 2026-06-20  | 2300.00 | APROVADO  |\n|  3 |          2 | 2025-12-01  |  500.00 | ENTREGUE  |\n|  4 |          2 | 2026-02-10  | 1200.00 | CANCELADO |\n|  5 |          3 | 2026-07-10  | 3200.00 | PENDENTE  |\n|  6 |          4 | 2026-03-05  |  800.00 | ENTREGUE  |\n|  7 |          4 | 2026-05-18  | 1800.00 | ENTREGUE  |\n|  8 |          4 | 2026-07-01  |  950.00 | APROVADO  |\n+----+------------+-------------+---------+-----------+\n8 rows in set (0.00 sec)<\/code><\/pre>\n<p>Agora implementaremos a fun\u00e7\u00e3o que, para um dado cliente, calcula o total gasto em pedidos <strong>ENTREGUE<\/strong>, conta quantos pedidos est\u00e3o pendentes e retorna uma classifica\u00e7\u00e3o textual. Utilizaremos cursor para percorrer os pedidos do cliente e um handler para capturar a condi\u00e7\u00e3o de &#8220;nenhum pedido encontrado&#8221;:<\/p>\n<pre><code>DELIMITER $$\n\nCREATE FUNCTION obter_status_cliente(p_cliente_id INT)\nRETURNS VARCHAR(100)\nREADS SQL DATA\nNOT DETERMINISTIC\nCOMMENT 'Retorna status do cliente baseado em seu hist\u00f3rico de pedidos'\nBEGIN\n    DECLARE v_total_entregue DECIMAL(10,2) DEFAULT 0;\n    DECLARE v_qtd_pendentes INT DEFAULT 0;\n    DECLARE v_status_pedido VARCHAR(20);\n    DECLARE v_valor_pedido DECIMAL(10,2);\n    DECLARE v_finalizado INT DEFAULT 0;\n    DECLARE v_status_final VARCHAR(100);\n    \n    -- Cursor para iterar sobre os pedidos do cliente\n    DECLARE cur_pedidos CURSOR FOR \n        SELECT status, valor \n        FROM pedidos \n        WHERE cliente_id = p_cliente_id;\n    \n    -- Handler: quando n\u00e3o houver mais linhas, define v_finalizado = 1\n    DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finalizado = 1;\n    \n    -- Verifica\u00e7\u00e3o inicial: cliente existe?\n    IF NOT EXISTS (SELECT 1 FROM clientes WHERE id = p_cliente_id) THEN\n        RETURN 'ERRO: Cliente n\u00e3o encontrado';\n    END IF;\n    \n    -- Abrir o cursor e iterar\n    OPEN cur_pedidos;\n    \n    loop_pedidos: LOOP\n        FETCH cur_pedidos INTO v_status_pedido, v_valor_pedido;\n        \n        -- Se o handler foi acionado (NOT FOUND), sair do loop\n        IF v_finalizado = 1 THEN\n            LEAVE loop_pedidos;\n        END IF;\n        \n        -- Acumular totais conforme o status\n        IF v_status_pedido = 'ENTREGUE' THEN\n            SET v_total_entregue = v_total_entregue + v_valor_pedido;\n        ELSEIF v_status_pedido = 'PENDENTE' THEN\n            SET v_qtd_pendentes = v_qtd_pendentes + 1;\n        END IF;\n    END LOOP loop_pedidos;\n    \n    CLOSE cur_pedidos;\n    \n    -- Construir a string de status baseada nos valores acumulados\n    IF v_total_entregue = 0 AND v_qtd_pendentes = 0 THEN\n        SET v_status_final = 'SEM HIST\u00d3RICO';\n    ELSEIF v_total_entregue >= 2000 THEN\n        SET v_status_final = CONCAT('VIP - Total entregue: R$ ', FORMAT(v_total_entregue, 2));\n    ELSE\n        SET v_status_final = CONCAT('REGULAR - Total entregue: R$ ', FORMAT(v_total_entregue, 2));\n    END IF;\n    \n    IF v_qtd_pendentes > 0 THEN\n        SET v_status_final = CONCAT(v_status_final, ' | Pend\u00eancias: ', v_qtd_pendentes);\n    END IF;\n    \n    RETURN v_status_final;\nEND $$\n\nDELIMITER ;<\/code><\/pre>\n<p>Este c\u00f3digo introduz v\u00e1rios conceitos avan\u00e7ados simultaneamente. O <strong>DECLARE CURSOR<\/strong> define uma consulta que ser\u00e1 percorrida linha a linha \u2014 diferentemente de um <strong>SELECT<\/strong> comum, o cursor permite processamento procedural sobre cada registro retornado. O <strong>DECLARE CONTINUE HANDLER FOR NOT FOUND<\/strong> \u00e9 um tratador de exce\u00e7\u00e3o que captura o sinal de &#8220;fim do resultset&#8221;: quando um <strong>FETCH<\/strong> n\u00e3o encontra mais linhas, ao inv\u00e9s de lan\u00e7ar um erro, o handler define a vari\u00e1vel <strong>v_finalizado<\/strong> para 1, permitindo que o loop seja encerrado graciosamente pelo comando <strong>LEAVE<\/strong>. A estrutura <strong>LOOP&#8230;END LOOP<\/strong> cria um la\u00e7o infinito controlado manualmente \u2014 uma alternativa ao <strong>WHILE<\/strong> que oferece maior flexibilidade no ponto de sa\u00edda. Observe tamb\u00e9m que utilizamos <strong>NOT DETERMINISTIC<\/strong> porque a fun\u00e7\u00e3o consulta tabelas cujos dados podem mudar entre chamadas.<\/p>\n<p>Vamos executar testes para verificar o comportamento da fun\u00e7\u00e3o em diferentes cen\u00e1rios:<\/p>\n<pre><code>-- Testes da fun\u00e7\u00e3o obter_status_cliente\nSELECT \n    id,\n    nome,\n    obter_status_cliente(id) AS status_cliente\nFROM clientes\nORDER BY id;\n\n-- Teste com cliente inexistente\nSELECT obter_status_cliente(999) AS cliente_inexistente;<\/code><\/pre>\n<pre><code class=\"output\">+----+------------------+---------------------------------------------------+\n| id | nome             | status_cliente                                    |\n+----+------------------+---------------------------------------------------+\n|  1 | Ana Silva        | VIP - Total entregue: R$ 1,500.00                 |\n|  2 | Carlos Oliveira  | REGULAR - Total entregue: R$ 500.00               |\n|  3 | Mariana Santos   | REGULAR - Total entregue: R$ 0.00 | Pend\u00eancias: 1 |\n|  4 | Roberto Almeida  | VIP - Total entregue: R$ 2,600.00                 |\n|  5 | Juliana Costa    | SEM HIST\u00d3RICO                                     |\n+----+------------------+---------------------------------------------------+\n5 rows in set (0.01 sec)\n\n+---------------------------+\n| cliente_inexistente       |\n+---------------------------+\n| ERRO: Cliente n\u00e3o encontrado |\n+---------------------------+\n1 row in set (0.00 sec)<\/code><\/pre>\n<h3>Gerenciando Functions: ALTER, DROP e SHOW<\/h3>\n<p>Diferentemente das tabelas, que podem ser alteradas com <strong>ALTER TABLE<\/strong>, as <strong>functions<\/strong> no MySQL n\u00e3o suportam um comando <strong>ALTER FUNCTION<\/strong> para modificar seu corpo. Para alterar uma fun\u00e7\u00e3o existente, voc\u00ea precisa remov\u00ea-la com <strong>DROP FUNCTION<\/strong> e recri\u00e1-la com as modifica\u00e7\u00f5es desejadas. Este \u00e9 um ponto importante de planejamento: em ambientes de produ\u00e7\u00e3o, recomendamos versionar todas as fun\u00e7\u00f5es em scripts SQL armazenados em reposit\u00f3rio Git e aplicar as altera\u00e7\u00f5es de forma controlada. Na JRT Technology Solutions, utilizamos pipelines de CI\/CD que executam <strong>DROP FUNCTION IF EXISTS<\/strong> seguido de <strong>CREATE FUNCTION<\/strong> com a nova defini\u00e7\u00e3o, garantindo atomicidade e rastreabilidade das mudan\u00e7as. Vamos ver os comandos de gerenciamento na pr\u00e1tica:<\/p>\n<pre><code>-- Listar todas as functions do banco de dados atual\nSHOW FUNCTION STATUS WHERE Db = 'aula_functions'\\G\n\n-- Exibir o c\u00f3digo-fonte de uma function espec\u00edfica\nSHOW CREATE FUNCTION calcular_idade\\G\n\n-- Remover uma function (DROP)\nDROP FUNCTION IF EXISTS formatar_cpf;\n\n-- Recriar a function com altera\u00e7\u00f5es (exemplo: incluindo valida\u00e7\u00e3o adicional)\nDELIMITER $$\n\nCREATE FUNCTION formatar_cpf(cpf_bruto VARCHAR(20))\nRETURNS VARCHAR(14)\nDETERMINISTIC\nCONTAINS SQL\nCOMMENT 'Formata um CPF removendo caracteres n\u00e3o num\u00e9ricos e aplicando m\u00e1scara | Vers\u00e3o 2.0'\nBEGIN\n    DECLARE cpf_limpo VARCHAR(11);\n    DECLARE cpf_formatado VARCHAR(14);\n    \n    -- Tratar NULL explicitamente\n    IF cpf_bruto IS NULL THEN\n        RETURN NULL;\n    END IF;\n    \n    SET cpf_limpo = REGEXP_REPLACE(cpf_bruto, '[^0-9]', '');\n    \n    IF CHAR_LENGTH(cpf_limpo) != 11 THEN\n        RETURN NULL;\n    END IF;\n    \n    -- Valida\u00e7\u00e3o extra: n\u00e3o permite CPF com todos d\u00edgitos iguais (ex: 111.111.111-11)\n    IF cpf_limpo REGEXP '^(0{11}|1{11}|2{11}|3{11}|4{11}|5{11}|6{11}|7{11}|8{11}|9{11})$' THEN\n        RETURN NULL;\n    END IF;\n    \n    SET cpf_formatado = CONCAT(\n        SUBSTRING(cpf_limpo, 1, 3), '.',\n        SUBSTRING(cpf_limpo, 4, 3), '.',\n        SUBSTRING(cpf_limpo, 7, 3), '-',\n        SUBSTRING(cpf_limpo, 10, 2)\n    );\n    \n    RETURN cpf_formatado;\nEND $$\n\nDELIMITER ;<\/code><\/pre>\n<pre><code class=\"output\">*************************** 1. row ***************************\n                  Db: aula_functions\n                Name: calcular_idade\n                Type: FUNCTION\n             Definer: root@localhost\n            Modified: 2026-07-24 10:15:32\n             Created: 2026-07-24 10:15:32\n       Security_type: DEFINER\n             Comment: Calcula a idade em anos com base na data de nascimento\ncharacter_set_client: utf8mb4\ncollation_connection: utf8mb4_unicode_ci\n  Database Collation: utf8mb4_unicode_ci\n*************************** 2. row ***************************\n                  Db: aula_functions\n                Name: obter_status_cliente\n                Type: FUNCTION\n             Definer: root@localhost\n            Modified: 2026-07-24 10:45:00\n             Created: 2026-07-24 10:45:00\n       Security_type: DEFINER\n             Comment: Retorna status do cliente baseado em seu hist\u00f3rico de pedidos\ncharacter_set_client: utf8mb4\ncollation_connection: utf8mb4_unicode_ci\n  Database Collation: utf8mb4_unicode_ci\n\nQuery OK, 0 rows affected (0.01 sec)\n\nQuery OK, 0 rows affected (0.02 sec)<\/code><\/pre>\n<p>Para ambientes que exigem documenta\u00e7\u00e3o e auditoria rigorosas, voc\u00ea pode consultar a tabela de metadados <strong>information_schema.ROUTINES<\/strong>, que oferece uma vis\u00e3o completa de todas as rotinas (functions e procedures) do servidor. Esta consulta nos ajuda a mapear rapidamente todo o invent\u00e1rio de fun\u00e7\u00f5es de um schema \u2014 algo que fazemos rotineiramente em projetos de migra\u00e7\u00e3o na JRT Technology Solutions:<\/p>\n<pre><code>-- Consulta avan\u00e7ada de metadados de functions\nSELECT \n    ROUTINE_NAME AS nome_funcao,\n    ROUTINE_TYPE AS tipo,\n    DATA_TYPE AS tipo_retorno,\n    CHARACTER_MAXIMUM_LENGTH AS comprimento_max,\n    IS_DETERMINISTIC AS deterministica,\n    SQL_DATA_ACCESS AS acesso_dados,\n    SECURITY_TYPE AS seguranca,\n    CREATED AS criada_em,\n    LAST_ALTERED AS ultima_alteracao\nFROM information_schema.ROUTINES\nWHERE ROUTINE_SCHEMA = 'aula_functions' \n  AND ROUTINE_TYPE = 'FUNCTION'\nORDER BY ROUTINE_NAME;<\/code><\/pre>\n<pre><code class=\"output\">+----------------------+----------+--------------+----------------+----------------+---------------+---------------+---------------------+---------------------+\n| nome_funcao          | tipo     | tipo_retorno | comprimento_max | deterministica | acesso_dados  | seguranca     | criada_em           | ultima_alteracao    |\n+----------------------+----------+--------------+----------------+----------------+---------------+---------------+---------------------+---------------------+\n| calcular_idade       | FUNCTION | int          |           NULL | YES            | READS SQL DATA| DEFINER       | 2026-07-24 10:15:32 | 2026-07-24 10:15:32 |\n| formatar_cpf         | FUNCTION | varchar      |             14 | YES            | CONTAINS SQL  | DEFINER       | 2026-07-24 11:00:00 | 2026-07-24 11:00:00 |\n| obter_status_cliente | FUNCTION | varchar      |            100 | NO             | READS SQL DATA| DEFINER       | 2026-07-24 10:45:00 | 2026-07-24 10:45:00 |\n+----------------------+----------+--------------+----------------+----------------+---------------+---------------+---------------------+---------------------+\n3 rows in set (0.00 sec)<\/code><\/pre>\n<h3>Verificando a Instala\u00e7\u00e3o \/ Testando a Configura\u00e7\u00e3o<\/h3>\n<p>Ap\u00f3s criar suas fun\u00e7\u00f5es, \u00e9 fundamental executar uma bateria de verifica\u00e7\u00f5es para garantir que tudo est\u00e1 operando conforme esperado. Esta se\u00e7\u00e3o \u00e9 obrigat\u00f3ria em nosso fluxo de valida\u00e7\u00e3o \u2014 na JRT Technology Solutions, nenhum deploy \u00e9 conclu\u00eddo sem que todos os testes de verifica\u00e7\u00e3o sejam executados e documentados. Vamos seguir um checklist sistem\u00e1tico:<\/p>\n<pre><code>-- 1. CONFIRMAR QUE TODAS AS FUNCTIONS EST\u00c3O LISTADAS\nSELECT COUNT(*) AS total_functions \nFROM information_schema.ROUTINES \nWHERE ROUTINE_SCHEMA = 'aula_functions' \n  AND ROUTINE_TYPE = 'FUNCTION';\n\n-- 2. TESTAR O RETORNO DE TIPOS ESPERADOS\nSELECT \n    calcular_idade('2010-06-15') AS teste_idade,\n    formatar_cpf('11122233344') AS teste_cpf,\n    obter_status_cliente(1) AS teste_status;\n\n-- 3. TESTAR COMPORTAMENTO COM VALORES NULOS E INV\u00c1LIDOS\nSELECT \n    calcular_idade(NULL) AS idade_nula,\n    formatar_cpf('123') AS cpf_invalido,\n    obter_status_cliente(999) AS cliente_inexistente;\n\n-- 4. VERIFICAR PERMISS\u00d5ES E DEFINER\nSELECT \n    ROUTINE_NAME,\n    DEFINER,\n    SECURITY_TYPE\nFROM information_schema.ROUTINES\nWHERE ROUTINE_SCHEMA = 'aula_functions'\n  AND ROUTINE_TYPE = 'FUNCTION';<\/code><\/pre>\n<pre><code class=\"output\">+-----------------+<br \/>\n| total_functions |<br \/>\n+-----------------+<br \/>\n|               3 |<br \/>\n+-----------------+<br \/>\n1 row in set (0.00 sec)<\/p>\n<p>+-------------+----------------+---------------------------------------------+<br \/>\n| teste_idade | teste_cpf      | teste_status                                |<br \/>\n+-------------+----------------+---------------------------------------------+<br \/>\n|          16 | 111.222.333-44 | VIP - Total entregue: R$ 1,500.00           |<br \/>\n+-------------+----------------+---------------------------------------------+<br \/>\n1 row in set (0.00 sec)<\/p>\n<p>+------------+----------------------+---------------------------+<br \/>\n| idade_nula | cpf_invalido         | cliente_inexistente       |<br \/>\n+------------+----------------------+---------------------------+<br \/>\n|       NULL | NULL                 | ERRO: Cliente n\u00e3o encontrado |<br \/>\n+------------+----------------------+---------------------------+<br \/>\n1 row in set (0.00 sec)<\/p>\n<p>+----------------------+----------------+---------------+<br \/>\n| ROUTINE_NAME         | DEFINER        | SECURITY_TYPE |<br \/>\n+----------------------+----------------+---------------+<br \/>\n| calcular_idade       | root@localhost | DEFINER       |<br \/>\n| formatar_cpf         | root@localhost | DEFINER       |<br \/>\n| obter_status_cl<\/p>\n<div style=\"margin:52px 0 40px;padding:36px 28px;background:linear-gradient(135deg,#0f172a 0%,#1a2744 100%);border:2px solid #25D366;border-radius:18px;text-align:center;box-shadow:0 4px 28px rgba(37,211,102,0.18)\">\n<p style=\"margin:0 0 10px;font-size:18px;color:#ffffff;font-weight:700;line-height:1.4\">Quer aprender na pr\u00e1tica com especialistas?<\/p>\n<p style=\"margin:0 0 28px;font-size:15px;color:#94a3b8;font-weight:400;line-height:1.6\">A JRT Technology Solutions oferece treinamentos e implementa\u00e7\u00e3o de MySQL para equipes corporativas.<\/p>\n<p>  <a href=\"https:\/\/api.whatsapp.com\/send\/?phone=5521980606699&#038;text=Ol%C3%A1!%20Tenho%20interesse%20no%20treinamento%20de%20MySQL.&#038;type=phone_number&#038;app_absent=0\"\n     target=\"_blank\" rel=\"noopener noreferrer\"\n     style=\"display:inline-flex;align-items:center;gap:12px;background:#25D366;color:#ffffff;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;font-size:16px;font-weight:700;padding:15px 32px;border-radius:100px;text-decoration:none;box-shadow:0 4px 16px rgba(37,211,102,0.45);letter-spacing:0.01em\"><br \/>\n    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"#ffffff\"><path d=\"M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z\"\/><\/svg><br \/>\n    Falar no WhatsApp<br \/>\n  <\/a>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Aprenda a criar fun\u00e7\u00f5es customizadas no MySQL e potencialize suas consultas. Descubra tudo na Aula 17 do curso &#8220;MySQL \u2014 Do Zero ao Avan\u00e7ado&#8221;!<\/p>\n","protected":false},"author":1,"featured_media":1774,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"iawp_total_views":0,"footnotes":""},"categories":[75],"tags":[2870,2871,120,2663,1160,241],"class_list":["post-1775","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devops","tag-funcoes-customizadas-mysql","tag-funcoes-em-banco-de-dados","tag-mysql","tag-programacao-mysql","tag-sql-avancado","tag-tutorial-mysql"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.0.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"Aprenda a criar fun\u00e7\u00f5es customizadas no MySQL e potencialize suas consultas. Descubra tudo na Aula 17 do curso &quot;MySQL \u2014 Do Zero ao Avan\u00e7ado&quot;!\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Thiago Paes Rodrigues\"\/>\n\t<meta name=\"google-site-verification\" content=\"QKPfpDCzHmzKyfFk5j1KZW3HhROYTPeqwBN5qcJ8qcg\" \/>\n\t<link rel=\"canonical\" href=\"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.0.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pt_BR\" \/>\n\t\t<meta property=\"og:site_name\" content=\"BLOG - JRT Technology Solutions - Um espa\u00e7o dedicado a explorar o universo da tecnologia de forma clara, pr\u00e1tica e atual. Aqui voc\u00ea encontra novidades, an\u00e1lises, tutoriais e reflex\u00f5es sobre inova\u00e7\u00e3o, intelig\u00eancia artificial, gadgets, programa\u00e7\u00e3o e tend\u00eancias digitais. Nosso objetivo \u00e9 simplificar o complexo, ajudar voc\u00ea a se manter atualizado e transformar conhecimento em pr\u00e1tica no seu dia a dia.\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"Aula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL - BLOG - JRT Technology Solutions\" \/>\n\t\t<meta property=\"og:description\" content=\"Aprenda a criar fun\u00e7\u00f5es customizadas no MySQL e potencialize suas consultas. Descubra tudo na Aula 17 do curso &quot;MySQL \u2014 Do Zero ao Avan\u00e7ado&quot;!\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/jrtx.com.br\/blog\/wp-content\/uploads\/2026\/03\/cropped-logo-mini.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/jrtx.com.br\/blog\/wp-content\/uploads\/2026\/03\/cropped-logo-mini.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"100\" \/>\n\t\t<meta property=\"og:image:height\" content=\"75\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2026-07-24T21:02:11+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2026-07-24T21:02:11+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/profile.php?id=61590814880509\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n\t\t<meta name=\"twitter:title\" content=\"Aula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL - BLOG - JRT Technology Solutions\" \/>\n\t\t<meta name=\"twitter:description\" content=\"Aprenda a criar fun\u00e7\u00f5es customizadas no MySQL e potencialize suas consultas. Descubra tudo na Aula 17 do curso &quot;MySQL \u2014 Do Zero ao Avan\u00e7ado&quot;!\" \/>\n\t\t<meta name=\"twitter:image\" content=\"https:\/\/jrtx.com.br\/blog\/wp-content\/uploads\/2026\/03\/cropped-logo-mini.jpg\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"BlogPosting\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/2026\\\/07\\\/24\\\/aula-17-functions-funcoes-customizadas-no-mysql\\\/#blogposting\",\"name\":\"Aula 17: Functions \\u2014 fun\\u00e7\\u00f5es customizadas no MySQL - BLOG - JRT Technology Solutions\",\"headline\":\"Aula 17: Functions \\u2014 fun\\u00e7\\u00f5es customizadas no MySQL\",\"author\":{\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/author\\\/thiago\\\/#author\"},\"publisher\":{\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/#organization\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/ai-image-1784926919626.jpg\",\"width\":1440,\"height\":1024,\"caption\":\"Aula 17: Functions \\u2014 fun\\u00e7\\u00f5es customizadas no MySQL\"},\"datePublished\":\"2026-07-24T18:02:11-03:00\",\"dateModified\":\"2026-07-24T18:02:11-03:00\",\"inLanguage\":\"pt-BR\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/2026\\\/07\\\/24\\\/aula-17-functions-funcoes-customizadas-no-mysql\\\/#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/2026\\\/07\\\/24\\\/aula-17-functions-funcoes-customizadas-no-mysql\\\/#webpage\"},\"articleSection\":\"DevOps, fun\\u00e7\\u00f5es customizadas MySQL, fun\\u00e7\\u00f5es em banco de dados, MySQL, programa\\u00e7\\u00e3o MySQL, SQL avan\\u00e7ado, tutorial mysql\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/2026\\\/07\\\/24\\\/aula-17-functions-funcoes-customizadas-no-mysql\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/jrtx.com.br\\\/blog\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/category\\\/devops\\\/#listItem\",\"name\":\"DevOps\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/category\\\/devops\\\/#listItem\",\"position\":2,\"name\":\"DevOps\",\"item\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/category\\\/devops\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/2026\\\/07\\\/24\\\/aula-17-functions-funcoes-customizadas-no-mysql\\\/#listItem\",\"name\":\"Aula 17: Functions \\u2014 fun\\u00e7\\u00f5es customizadas no MySQL\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/2026\\\/07\\\/24\\\/aula-17-functions-funcoes-customizadas-no-mysql\\\/#listItem\",\"position\":3,\"name\":\"Aula 17: Functions \\u2014 fun\\u00e7\\u00f5es customizadas no MySQL\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/category\\\/devops\\\/#listItem\",\"name\":\"DevOps\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/#organization\",\"name\":\"JRT Technology Solutions | Tecnologia e Inova\\u00e7\\u00e3o para Empresas\",\"description\":\"Um espa\\u00e7o dedicado a explorar o universo da tecnologia de forma clara, pr\\u00e1tica e atual. Aqui voc\\u00ea encontra novidades, an\\u00e1lises, tutoriais e reflex\\u00f5es sobre inova\\u00e7\\u00e3o, intelig\\u00eancia artificial, gadgets, programa\\u00e7\\u00e3o e tend\\u00eancias digitais. Nosso objetivo \\u00e9 simplificar o complexo, ajudar voc\\u00ea a se manter atualizado e transformar conhecimento em pr\\u00e1tica no seu dia a dia.\",\"url\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/\",\"telephone\":\"+552138277513\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/cropped-logo-mini.jpg\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/2026\\\/07\\\/24\\\/aula-17-functions-funcoes-customizadas-no-mysql\\\/#organizationLogo\",\"width\":100,\"height\":75},\"image\":{\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/2026\\\/07\\\/24\\\/aula-17-functions-funcoes-customizadas-no-mysql\\\/#organizationLogo\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/profile.php?id=61590814880509\",\"https:\\\/\\\/www.instagram.com\\\/jrtx.tech\\\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/author\\\/thiago\\\/#author\",\"url\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/author\\\/thiago\\\/\",\"name\":\"Thiago Paes Rodrigues\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/2026\\\/07\\\/24\\\/aula-17-functions-funcoes-customizadas-no-mysql\\\/#authorImage\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/3cdfdf5f766c59d9c9acab959751c31c3442acd94d4b2927c51d2a0c31b50822?s=96&d=mm&r=g\",\"width\":96,\"height\":96,\"caption\":\"Thiago Paes Rodrigues\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/2026\\\/07\\\/24\\\/aula-17-functions-funcoes-customizadas-no-mysql\\\/#webpage\",\"url\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/2026\\\/07\\\/24\\\/aula-17-functions-funcoes-customizadas-no-mysql\\\/\",\"name\":\"Aula 17: Functions \\u2014 fun\\u00e7\\u00f5es customizadas no MySQL - BLOG - JRT Technology Solutions\",\"description\":\"Aprenda a criar fun\\u00e7\\u00f5es customizadas no MySQL e potencialize suas consultas. Descubra tudo na Aula 17 do curso \\\"MySQL \\u2014 Do Zero ao Avan\\u00e7ado\\\"!\",\"inLanguage\":\"pt-BR\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/2026\\\/07\\\/24\\\/aula-17-functions-funcoes-customizadas-no-mysql\\\/#breadcrumblist\"},\"author\":{\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/author\\\/thiago\\\/#author\"},\"creator\":{\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/author\\\/thiago\\\/#author\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/ai-image-1784926919626.jpg\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/2026\\\/07\\\/24\\\/aula-17-functions-funcoes-customizadas-no-mysql\\\/#mainImage\",\"width\":1440,\"height\":1024,\"caption\":\"Aula 17: Functions \\u2014 fun\\u00e7\\u00f5es customizadas no MySQL\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/2026\\\/07\\\/24\\\/aula-17-functions-funcoes-customizadas-no-mysql\\\/#mainImage\"},\"datePublished\":\"2026-07-24T18:02:11-03:00\",\"dateModified\":\"2026-07-24T18:02:11-03:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/\",\"name\":\"JRT Technology Solutions | Tecnologia e Inova\\u00e7\\u00e3o para Empresas\",\"alternateName\":\"JRT Technology Solutions | Tecnologia e Inova\\u00e7\\u00e3o para Empresas\",\"description\":\"Um espa\\u00e7o dedicado a explorar o universo da tecnologia de forma clara, pr\\u00e1tica e atual. Aqui voc\\u00ea encontra novidades, an\\u00e1lises, tutoriais e reflex\\u00f5es sobre inova\\u00e7\\u00e3o, intelig\\u00eancia artificial, gadgets, programa\\u00e7\\u00e3o e tend\\u00eancias digitais. Nosso objetivo \\u00e9 simplificar o complexo, ajudar voc\\u00ea a se manter atualizado e transformar conhecimento em pr\\u00e1tica no seu dia a dia.\",\"inLanguage\":\"pt-BR\",\"publisher\":{\"@id\":\"https:\\\/\\\/jrtx.com.br\\\/blog\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"Aula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL - BLOG - JRT Technology Solutions","description":"Aprenda a criar fun\u00e7\u00f5es customizadas no MySQL e potencialize suas consultas. Descubra tudo na Aula 17 do curso \"MySQL \u2014 Do Zero ao Avan\u00e7ado\"!","canonical_url":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/","robots":"max-image-preview:large","keywords":"","webmasterTools":{"google-site-verification":"QKPfpDCzHmzKyfFk5j1KZW3HhROYTPeqwBN5qcJ8qcg","miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"BlogPosting","@id":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/#blogposting","name":"Aula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL - BLOG - JRT Technology Solutions","headline":"Aula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL","author":{"@id":"https:\/\/jrtx.com.br\/blog\/author\/thiago\/#author"},"publisher":{"@id":"https:\/\/jrtx.com.br\/blog\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/jrtx.com.br\/blog\/wp-content\/uploads\/2026\/07\/ai-image-1784926919626.jpg","width":1440,"height":1024,"caption":"Aula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL"},"datePublished":"2026-07-24T18:02:11-03:00","dateModified":"2026-07-24T18:02:11-03:00","inLanguage":"pt-BR","mainEntityOfPage":{"@id":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/#webpage"},"isPartOf":{"@id":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/#webpage"},"articleSection":"DevOps, fun\u00e7\u00f5es customizadas MySQL, fun\u00e7\u00f5es em banco de dados, MySQL, programa\u00e7\u00e3o MySQL, SQL avan\u00e7ado, tutorial mysql"},{"@type":"BreadcrumbList","@id":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/jrtx.com.br\/blog#listItem","position":1,"name":"Home","item":"https:\/\/jrtx.com.br\/blog","nextItem":{"@type":"ListItem","@id":"https:\/\/jrtx.com.br\/blog\/category\/devops\/#listItem","name":"DevOps"}},{"@type":"ListItem","@id":"https:\/\/jrtx.com.br\/blog\/category\/devops\/#listItem","position":2,"name":"DevOps","item":"https:\/\/jrtx.com.br\/blog\/category\/devops\/","nextItem":{"@type":"ListItem","@id":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/#listItem","name":"Aula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL"},"previousItem":{"@type":"ListItem","@id":"https:\/\/jrtx.com.br\/blog#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/#listItem","position":3,"name":"Aula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL","previousItem":{"@type":"ListItem","@id":"https:\/\/jrtx.com.br\/blog\/category\/devops\/#listItem","name":"DevOps"}}]},{"@type":"Organization","@id":"https:\/\/jrtx.com.br\/blog\/#organization","name":"JRT Technology Solutions | Tecnologia e Inova\u00e7\u00e3o para Empresas","description":"Um espa\u00e7o dedicado a explorar o universo da tecnologia de forma clara, pr\u00e1tica e atual. Aqui voc\u00ea encontra novidades, an\u00e1lises, tutoriais e reflex\u00f5es sobre inova\u00e7\u00e3o, intelig\u00eancia artificial, gadgets, programa\u00e7\u00e3o e tend\u00eancias digitais. Nosso objetivo \u00e9 simplificar o complexo, ajudar voc\u00ea a se manter atualizado e transformar conhecimento em pr\u00e1tica no seu dia a dia.","url":"https:\/\/jrtx.com.br\/blog\/","telephone":"+552138277513","logo":{"@type":"ImageObject","url":"https:\/\/jrtx.com.br\/blog\/wp-content\/uploads\/2026\/03\/cropped-logo-mini.jpg","@id":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/#organizationLogo","width":100,"height":75},"image":{"@id":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/#organizationLogo"},"sameAs":["https:\/\/www.facebook.com\/profile.php?id=61590814880509","https:\/\/www.instagram.com\/jrtx.tech\/"]},{"@type":"Person","@id":"https:\/\/jrtx.com.br\/blog\/author\/thiago\/#author","url":"https:\/\/jrtx.com.br\/blog\/author\/thiago\/","name":"Thiago Paes Rodrigues","image":{"@type":"ImageObject","@id":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/3cdfdf5f766c59d9c9acab959751c31c3442acd94d4b2927c51d2a0c31b50822?s=96&d=mm&r=g","width":96,"height":96,"caption":"Thiago Paes Rodrigues"}},{"@type":"WebPage","@id":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/#webpage","url":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/","name":"Aula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL - BLOG - JRT Technology Solutions","description":"Aprenda a criar fun\u00e7\u00f5es customizadas no MySQL e potencialize suas consultas. Descubra tudo na Aula 17 do curso \"MySQL \u2014 Do Zero ao Avan\u00e7ado\"!","inLanguage":"pt-BR","isPartOf":{"@id":"https:\/\/jrtx.com.br\/blog\/#website"},"breadcrumb":{"@id":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/#breadcrumblist"},"author":{"@id":"https:\/\/jrtx.com.br\/blog\/author\/thiago\/#author"},"creator":{"@id":"https:\/\/jrtx.com.br\/blog\/author\/thiago\/#author"},"image":{"@type":"ImageObject","url":"https:\/\/jrtx.com.br\/blog\/wp-content\/uploads\/2026\/07\/ai-image-1784926919626.jpg","@id":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/#mainImage","width":1440,"height":1024,"caption":"Aula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL"},"primaryImageOfPage":{"@id":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/#mainImage"},"datePublished":"2026-07-24T18:02:11-03:00","dateModified":"2026-07-24T18:02:11-03:00"},{"@type":"WebSite","@id":"https:\/\/jrtx.com.br\/blog\/#website","url":"https:\/\/jrtx.com.br\/blog\/","name":"JRT Technology Solutions | Tecnologia e Inova\u00e7\u00e3o para Empresas","alternateName":"JRT Technology Solutions | Tecnologia e Inova\u00e7\u00e3o para Empresas","description":"Um espa\u00e7o dedicado a explorar o universo da tecnologia de forma clara, pr\u00e1tica e atual. Aqui voc\u00ea encontra novidades, an\u00e1lises, tutoriais e reflex\u00f5es sobre inova\u00e7\u00e3o, intelig\u00eancia artificial, gadgets, programa\u00e7\u00e3o e tend\u00eancias digitais. Nosso objetivo \u00e9 simplificar o complexo, ajudar voc\u00ea a se manter atualizado e transformar conhecimento em pr\u00e1tica no seu dia a dia.","inLanguage":"pt-BR","publisher":{"@id":"https:\/\/jrtx.com.br\/blog\/#organization"}}]},"og:locale":"pt_BR","og:site_name":"BLOG - JRT Technology Solutions - Um espa\u00e7o dedicado a explorar o universo da tecnologia de forma clara, pr\u00e1tica e atual. Aqui voc\u00ea encontra novidades, an\u00e1lises, tutoriais e reflex\u00f5es sobre inova\u00e7\u00e3o, intelig\u00eancia artificial, gadgets, programa\u00e7\u00e3o e tend\u00eancias digitais. Nosso objetivo \u00e9 simplificar o complexo, ajudar voc\u00ea a se manter atualizado e transformar conhecimento em pr\u00e1tica no seu dia a dia.","og:type":"article","og:title":"Aula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL - BLOG - JRT Technology Solutions","og:description":"Aprenda a criar fun\u00e7\u00f5es customizadas no MySQL e potencialize suas consultas. Descubra tudo na Aula 17 do curso &quot;MySQL \u2014 Do Zero ao Avan\u00e7ado&quot;!","og:url":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/","og:image":"https:\/\/jrtx.com.br\/blog\/wp-content\/uploads\/2026\/03\/cropped-logo-mini.jpg","og:image:secure_url":"https:\/\/jrtx.com.br\/blog\/wp-content\/uploads\/2026\/03\/cropped-logo-mini.jpg","og:image:width":100,"og:image:height":75,"article:published_time":"2026-07-24T21:02:11+00:00","article:modified_time":"2026-07-24T21:02:11+00:00","article:publisher":"https:\/\/www.facebook.com\/profile.php?id=61590814880509","twitter:card":"summary_large_image","twitter:title":"Aula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL - BLOG - JRT Technology Solutions","twitter:description":"Aprenda a criar fun\u00e7\u00f5es customizadas no MySQL e potencialize suas consultas. Descubra tudo na Aula 17 do curso &quot;MySQL \u2014 Do Zero ao Avan\u00e7ado&quot;!","twitter:image":"https:\/\/jrtx.com.br\/blog\/wp-content\/uploads\/2026\/03\/cropped-logo-mini.jpg"},"aioseo_meta_data":{"post_id":"1775","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_custom_url":null,"og_image_custom_fields":null,"og_image_url":null,"og_image_width":null,"og_image_height":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_image_url":null,"twitter_title":null,"twitter_description":null,"schema_type":"default","schema_type_options":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"limit_modified_date":false,"ai":null,"breadcrumb_settings":null,"seo_analyzer_scan_date":null,"created":"2026-07-30 23:14:46","updated":"2026-07-30 23:14:46","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/jrtx.com.br\/blog\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/jrtx.com.br\/blog\/category\/devops\/\" title=\"DevOps\">DevOps<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tAula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/jrtx.com.br\/blog"},{"label":"DevOps","link":"https:\/\/jrtx.com.br\/blog\/category\/devops\/"},{"label":"Aula 17: Functions \u2014 fun\u00e7\u00f5es customizadas no MySQL","link":"https:\/\/jrtx.com.br\/blog\/2026\/07\/24\/aula-17-functions-funcoes-customizadas-no-mysql\/"}],"_links":{"self":[{"href":"https:\/\/jrtx.com.br\/blog\/wp-json\/wp\/v2\/posts\/1775","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jrtx.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jrtx.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jrtx.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jrtx.com.br\/blog\/wp-json\/wp\/v2\/comments?post=1775"}],"version-history":[{"count":0,"href":"https:\/\/jrtx.com.br\/blog\/wp-json\/wp\/v2\/posts\/1775\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jrtx.com.br\/blog\/wp-json\/wp\/v2\/media\/1774"}],"wp:attachment":[{"href":"https:\/\/jrtx.com.br\/blog\/wp-json\/wp\/v2\/media?parent=1775"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jrtx.com.br\/blog\/wp-json\/wp\/v2\/categories?post=1775"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jrtx.com.br\/blog\/wp-json\/wp\/v2\/tags?post=1775"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}