Por volta dos anos 80 foi desenvolvida pela Oracle Corporation uma extensão procedural do SQL conhecida como a linguagem de programação PL/SQL. O PL/SQL é na realidade uma combinação do SQL com os demais recursos oferecidos juntamente com uma linguagem de programação. A Oracle usa uma engine para processar as instruções, estas por sua vez podem ser armazenadas tanto do lado servidor, numa base de dados, por exemplo, ou no lado cliente. Dentre várias razões para a utilização do PL/SQL seguem abaixo alguns de seus fatos mais notáveis:

  • É completamente portável, com uma linguagem transacional de informações de alta performance.
  • Ela provê de um interpretador embutido e independente de sistema operacional.
  • Ela pode ser chamada diretamente a partir de linhas de comandos através de uma interface chamada SQL*PLUS.
  • A sua sintaxe básica é baseada nas linguagens de programação pascal e ADA.
  • Além da Oracle, a PL/SQL é utilizada também na IMB DB2.

Os recursos oferecidos por ela destacam-se uma extensiva verificação de erros, uma grande variedade de estruturas de programação, suporte ao desenvolvimento de aplicações web e também server pages e suporte à programação Orientada a Objetos.

Vantagens da utilização da PL/SQL

Como não poderia deixar de ser, a PL/SQL tem vantagens para a sua utilização no dia a dia que facilitam e muito a vida de desenvolvedores que agem também como DBA’s e buscam por melhores soluções de acordo com os projetos em desenvolvimento.

Dentre uma das principais vantagens, destaque-se o tanto o SQL estático (como operações DML controle de transações de blocos PL/SQL) quanto ao SQL dinâmico (é em casos de utilização de instruções DDL em blocos PL/SQL). Além disso, permite o envio de um bloco de instruções completo para o banco de dados em uma única vez. Isso é um ponto positivo, pois reduz o tráfico de rede e provê uma alta performance para as aplicações.

Outro item muito importante é a economia de tempo no design e em debugs através de poderosos recursos como o exception handling, o encapsulation, data hiding e tipos de dados orientados a objeto. Ou seja, cada um dos blocos forma uma unidade de tarefa ou um módulo lógico que pode ser armazenado e reutilizado.

Outro ponto a ser tratado é com relação a sua capacidade de linguagem procedural que consiste de construtores, assim como declarações condicionais, como por exemplo, declarações if-else, loops como do tipo for ou while.

E por último o tratamento de erros com error handling. As exceções duram o tempo de execução do programa PL/SQL. Uma vez esta exceção sendo capturada, dependendo do seu tipo, pode ser tomada decisões de acordo com o seu propósito. Como por exemplo, um tratamento de exceção em uma divisão entre dois números, onde o divisor seja passado como 0 (zero). A exceção para este tipo é utilizando a expressão DIVIDE_ZERO que já faz parte das exceções padrões do programa.

Trabalhando com placeholders PL/SQL

Placeholders são espaços reservados temporariamente para alocação de dados. Os placeholders podem ser qualquer tipo de variável, constantes ou records. A Oracle os define para armazenarem temporariamente os dados e após isso serem utilizados para manipular os dados durante a execução de blocos PL/SQL.

Dependendo do tipo de dado que pretendemos armazenar, podemos definir o tipo de placeholder com um nome e um tipo que será definido para ele. Alguns dos tipos mais comuns são o number(n,m), Char(n), Varchar2(n), Date, Long, Raw, Bfile, etc.

Placeholder: Variáveis PL/SQL

As variáveis são placeholders que armazenam valores que podem ser modificados no decorrer de um bloco PL/SQL. A sintaxe geral dela é passando-se o nome da variável e logo após o tipo de dado que ela irá armazenar. Observe a Listagem 1.

Listagem 1. Estrutura geral de uma variável.

variable_name datatype [NOT NULL := value ]; 

No exemplo acima estamos apresentando a estrutura básica de um placeholder do tipo variável que apresenta as seguintes informações:

  • Variable_name: nome que foi atribuído a variável.
  • Datatype é um tipo de dado válido para o PL/SQL.
  • NOT NULL: é uma especificação opcional na variável.
  • Value também é uma especificação opcional, já que podemos inicializar ou não a variável neste momento.
  • Cada declaração de variável, necessariamente deve ser passada por linhas e separadas por ponto e vírgula.

Para clarear um pouco mais o conceito de variáveis na PL/SQL, vejamos um exemplo simples na Listagem 2.

Listagem 2. Declarando variáveis no PL/SQL.


DECLARE
/* O declare é utilizado antes de iniciarmos um bloco de comandos no 
*PL/SQL e ele é opcional.
*/
Salario number(8,2);
Departamento Varchar2(50) NOT NULL := “Departamento 1”; 

No exemplo acima apenas definimos duas variáveis, onde a primeira não recebe parâmetros iniciais e é do tipo number. Já na segunda variável definimos para ela um parâmetro inicial e também a definimos como NOT NULL, o que diz que ela não pode ser nula.

Um exemplo mais completo de uma estrutura real de uso no PL/SQL seria igual ao da Listagem 3.

Listagem 3. Estrutura de bloco PL/SQL.

DECLARE 
 nsalario number(6); 
 nempregado_id number(6) = 1116;  
/* 
  atribuindo um valor para identificação da empresa no banco de dados.
*/ 
BEGIN – Inicio de um bloco propriamente dito na PL/SQL.
 SELECT salario 
 INTO nsalario
 FROM empregado 
 WHERE emp_id = nempregado_id; 
 dbms_output.put_line(nsalario); 
 dbms_output.put_line('O empregado ' 
               || nempresa_id || ' tem salario ' || nsalario); 
END;  -- Finalização do bloco.
  / -- A barra indica ao PL/SQL que a instrução 
  /-- está finalizada e pode ser executada. 

Escopo de variáveis

A PL/SQL permite o aninhamento de blocos com outros blocos, mas o que acontece com as variáveis? Se uma variável é acessível a um bloco externo, também será acessível aos blocos internos, já que estão aninhados. Porém, variáveis declaradas em blocos internos não são acessíveis aos blocos exteriores a elas. Com base nisso, podemos classificar as variáveis em dois tipos:

  • Variáveis globais: elas são declaradas no começo do bloco principal e pode ser referenciada por ele ou por blocos que estejam internos a ele.
  • Variáveis locais: Estas são acessíveis apenas nos blocos em que foram declaradas e não podem ser acessadas por blocos externos ou em níveis mais altos na cadeia de instruções.

Um simples exemplo para uma melhor visualização do que foi explicado acima é o que vemos na Listagem 4.

Listagem 4. Variáveis locais e variáveis globais.

DECLARE
 num1 number; 
 num2 number; 
 
 BEGIN 
  num1 := 100; 
  num2 := 200; 
  
DECLARE 
   mult number; 
      BEGIN 
          mult := num1 * num2; 
      END; 
END; 
/ 

Percebam que neste exemplo temos as variáveis globais (num1 e num2) que podem ser acessadas por um bloco interno e lá receber novos valores. Também temos uma variável que pode ser acessada apenas pelo bloco no qual ela foi declarada, que é o caso da variável “mult”. Esta última não pode ser acessada pelo primeiro bloco.

Placeholder: Constantes no PL/SQL

Como o próprio nome diz, constantes são valores que serão definidos uma única vez e não são alterados dentro de um bloco PL/SQL.

A estrutura base de uma constante é:

constant_name CONSTANT datatype := VALUE; 

Onde:

  • Constant_name: É o nome que será dado a nossa constante.
  • CONSTANT: palavra reservada que indica que a variável não poderá ser alterada.
  • Datatype: É o tipo de dado que normalmente é number.
  • Value: A atribuição de um valor que será seu parâmetro. Este não é do tipo opcional, ele deve ser declarado logo que criado.

Exemplos práticos é sempre a melhor maneira de visualizar o tipo de informação. Então digamos que tenhamos uma empresa onde tenhamos 200 funcionários e a cada ano daremos um aumento de 25% no salário deles. Como definiríamos isso? Com a utilização de uma constante, conforme o trecho de código da Listagem 5.

Listagem 5. Definindo constantes.

DECLARE 
    acrescimo CONSTANT number(3) := 0.25; 
BEGIN 
    salarioFuncionario := 2000;
    novoSalario := salarioFuncionario*(1 + acréscimo);  
    dbms_output.put_line (novoSalario); 
END; 

Tipos de dados PL/SQL

Como podemos perceber, tanto variáveis, quanto constantes devem ter um tipo de dado válido que possa especificar o seu formato de armazenagem, restrições e qual o intervalo de valores é permitido. Para não nos perdermos com relação aos diferentes tipos de dados, segue na Tabela 1 a apresentação das categorias e suas descrições.

Categoria

Descrição

Escalar

Valores individuais sem componentes internos, assim como é o caso do NUMBER, DATE ou BOOLEAN.

Large Object (LOB)

São ponteiros para objetos maiores armazenados separadamente de outros tipos de dados, assim como os tipos TEXT, GRAFIC IMAGE, VIDEO CLIPS.

Composto

São tipos de dados que apresentam componentes internos e que podem ser acessados separadamente. Exemplos dessa utilização: Records e collections.

Referência

Ponteiros para outros dados.

Tabela 1. Definição das categorias de tipos de dados e suas descrições.

*Os tipos Referência e Compostos não serão abordados neste artigo.

Já os tipos de dados escalares são definidos nas seguintes categorias da Tabela 2.

Tipos de dados

Descrição

Numeric

Valores numéricos em que as operações aritméticas são realizadas.

Character

Valores alfanuméricos que representam caracteres simples ou strings de caracteres.

Boolean

Valores lógicos nos quais as operações lógicas são realizadas.

Datetime

Datas e horas basicamente.

Tabela 2. Definição dos tipos de dados escalares.

A PL/SQL também provê subtipos de dados, como é o caso do tipo de dados NUMBER que possui um subtipo de dado do tipo INTEGER. Normalmente podemos utilizar subtipos de dados quando estamos trabalhando com outras linguagens de programação, como é o caso do Java, por exemplo.

Já na Tabela 3 definimos onde apresentamos cada um dos tipos numéricos pré-definidos pela PL/SQL e seus subtipos para que possamos conhecer melhor o nosso mundo nesta nova linguagem.

Tipo de dado

Descrição

PLS_INTEGER

Valores inteiros numa faixa de -2,147,483,648 a 2,147,483,647, representado em 32 bits.

BINARY_INTEGER

Valores inteiros numa faixa de -2,147,483,648 a 2,147,483,647, representado em 32 bits.

BINARY_FLOAT

Precisão simples de números flutuantes, definido pela IEEE 754.

BINARY_DOUBLE

Precisão dupla de números flutuantes, definido pela IEEE 754.

NUMBER (prec, scale)

Valores numéricos fixos ou de pontos flutuantes com valor absoluto numa margem de 1E-130 a 1.0E-126. Um NUMBER também pode ser definido como 0.

DEC (prec, scale)

A ANSI especifica como tipo de valor fixo com máxima precisão de 38 dígitos decimais.

DECIMAL (prec, scale)

A IBM especifica como tipo de valor fixo com máxima precisão de 38 dígitos decimais.

NUMERIC (prec, scale)

Ponto flutuante com precisão máxima de 38 dígitos decimais.

DOUBLE PRECISION

A ANSI especifica como tipo de valor fixo com máxima precisão de 38 dígitos decimais (126 binários).

FLOAT

A ANSI e a IBM especificam como tipo de valor fixo com máxima precisão de 38 dígitos decimais.

INT

A ANSI especifica como tipo inteiro com máxima precisão de 38 dígitos decimais.

INTEGER

A ANSI e a IBM especificam como tipo de valor inteiro com máxima precisão de 38 dígitos decimais.

SMALLINT

A ANSI e a IBM especificam como tipo de valor inteiro com máxima precisão de 38 dígitos decimais.

REAL

Tipo de ponto flutuante com máxima precisão de 63 dígitos binários, o que nos leva a aproximadamente 18 dígitos decimais.

Tabela 3. Definição dos tipos de dados numéricos.

Para exemplificar o conceito com relação aos tipos de dados numéricos segue abaixo na Listagem 6 um trecho de código, apresentando alguns dos tipos apresentados acima.

Listagem 6. Tipos de dados numéricos.

SET serveroutput ON;
  DECLARE
    nIdFuncionario binary_integer;
    nSalario NUMBER(10, 2);
    nAcrescimo FLOAT;
  BEGIN
    nidfuncionario := 25;
    nSalario       := 1500;
    nAcrescimo     := 0.25;
    dbms_output.put_line(‘O novo salário do funcionário: ’
     || nSalario*(1 + nAcrescimo));
  END; 

Na Tabela 4 temos a definição dos tipos de dados Character PL/SQL.

Tipo de dado

Descrição

CHAR

String de carateres de tamanho fixo com um tamanho máximo de 32.767 bytes.

VARCHAR2

String de carateres de tamanho variado com tamanho máximo de 32.767 bytes.

RAW

String de bites ou binários de tamanho variado com tamanho máximo de 32.767 bytes, não interpretados pela PL/SQL.

NCHAR

String de caracteres de tamanho fixo com tamanho máximo de 32.767 bytes.

NVARCHAR2

String de caracteres de tamanho variado com tamanho máximo de 32.767 bytes.

LONG

String de caracteres de tamanho variado com tamanho máximo de 32.760 bytes.

LONG RAW

String de caracteres de tamanho variado com tamanho máximo de 32.760 bytes, não interpretado pela PL/SQL.

ROWID

É o identificador físico da linha, o endereço de uma linha em uma tabela comum.

UROWID

Identificador de linha universal, podendo ele ser lógico, físico ou um identificador de linha externo.

Tabela 4. Definição dos tipos de dados Caracteres.

Para exemplificar o conceito com relação aos tipos de dados numéricos, segue abaixo na Listagem 7 um trecho de código apresentando alguns dos tipos mencionados acima.

Listagem 7. Tipos de dados character.

SET serveroutput ON;
  DECLARE
    nIdFuncionario binary_integer;
    nNome varchar2(100);
    nEstado CHAR(2);
  BEGIN
    nidfuncionario := 25;
    nNome       := ‘Edson Dionisio’;
    nEstado     := ‘PE’;
    dbms_output.put_line(‘Um dos leitores da devmedia se chama  ’
     || nNome || ‘ e mora no estado de  ’ || nEstado);
  END; 

Já os tipos de dados boolean armazenam apenas valores lógicos que são utilizados em operações lógicas. Estes valores lógicos podem ser de três tipos na PL/SQL, sendo estes True, False ou mesmo, o valor Null.

No entanto, a SQL não tem tipos de dados equivalentes ao boolean, portanto, os valores booleanos não podem ser usados em determinadas situações que são:

  • Instruções SQL.
  • Funções SQL embutidas, como por exemplo, utilizando o to_char().
  • Funções PL/SQL sendo chamadas por instruções SQL.

Para exemplificar o conceito com relação aos tipos de dados boolean, segue abaixo na Listagem 8 um trecho de código apresentando como utilizá-los.

Listagem 8. Tipos de dados boolean.

SET serveroutput ON;
  DECLARE
    nIdFuncionario binary_integer;
    nSalario  NUMBER(10, 2);
    nTipoReal BOOLEAN;
  BEGIN
    nidfuncionario := 25;
    nSalario       := 1500;
    nTipoReal      := TRUE;
    IF nTipoReal THEN
      dbms_output.put_line('O salário do funcionário ' 
      || nidfuncionario || ' é em Reais R

Com relação ao tipo de dado Date, é possível armazenar tamanhos fixos de dados relacionados a datas, que incluem horas do dia em segundos, por exemplo. O intervalo válido de datas é de 1 de janeiro, 4712 BC até 31 de dezembro, 9999 AD.

O formato de data padrão do Oracle é inicializado pelo parâmetro NLS_DATE_FORMAT. Como exemplo, o seu padrão pode ser definido como ‘DD-MON-YY’, que informa o dia com dois dígitos, a abreviação literal do nome do mês e os últimos dois dígitos do ano. Ele seria basicamente representado desta forma, 19-DEC-13. Cada data armazenada contém informações como o século, mês, dia, hora, minuto e segundo. Na Tabela 5 temos a representação dessas informações.

Nome do campo

Valor válido Datetime

Intervalo válido de valores

YEAR

-4712 a 9999, excluindo o ano 0.

Qualquer inteiro diferente de 0.

MONTH

01 a 12

0 a 11

DAY

01 a 31 (limitado pelo valor do mês e do ano de acordo com as regras do calendário local).

Qualquer inteiro diferente de 0.

HOUR

00 a 23

0 a 23

MINUTE

00 a 59

0 a 59

SECOND

00 a 59.9 (n)

0 a 59.9

TIMEZONE_HOUR

-12 a 14

Não aplicado.

TIMEZONE_MINUTE

00 a 59

Não aplicado.

TIMEZONE_REGION

Encontrado utilizando-se a view V$TIMEZONE_NAMES

Não aplicado.

TIMEZONE_ABBR

Encontrado utilizando-se a view V$TIMEZONE_NAMES

Não aplicado.

Tabela 5. Definição dos tipos de dados Datetime.

Para exemplificar o conceito com relação aos tipos de dados boolean, segue abaixo na Listagem 9 um trecho de código, apresentando como utilizá-lo.

Listagem 9. Tipos de dados Datetime.

SET serveroutput ON;
  DECLARE
    nIdFuncionario binary_integer;
    nSalario      NUMBER(10, 2);
    nTipoReal     BOOLEAN;
    dDataadmissao DATE;
  BEGIN
    nidfuncionario := 25;
    nSalario       := 1500;
    nTipoReal      := TRUE;
    dDataAdmissao  := '19/12/2013';
    IF nTipoReal THEN
      dbms_output.put_line('O salário do funcionário ' 
      || nidfuncionario || ' é em Reais R

Já o tipo de dados como LOB (Large Objects) referem-se a tipos de dados que fogem aos padrões explicados anteriormente, sendo estes postos em uma nova categoria de informações, assim como text, imagens gráficas, vídeo clipes e arquivos de áudio. O tipo de dados LOB permite de forma eficiente o acesso a estas informações de forma aleatória o que não ocorre com os outros tipos de dados já explanados. Abaixo temos a Tabela 6 contendo as informações referentes aos tipos suportados pelo PL/SQL LOB.

Tipo de dado

Descrição

Tamanho

BFILE

Utilizado para armazenar grandes objetos binários em arquivos do sistema operacional fora da base de dados.

Depende do sistema. Não pode exceder o tamanho de 4GB.

BLOB

Utilizado para armazenar grandes objetos binários na base de dados.

De 8 a 128 TB (Terabytes).

CLOB

Utilizado para armazenar grandes blocos de dados caracter na base de dados.

De 8 a 128 TB.

NCLOB

Utilizado para armazenar grandes blocos de dados NCHAR na base de dados.

De 8 a 128 TB.

Tabela 6. Tipos de dados LOB.

Subtipos definidos pelo usuário na PL/SQL

Como já dito anteriormente, um subtipo de dado é como uma variação de um determinado tipo de dado, que no caso seria o seu tipo base. A PL/SQL já possui vários subtipos pré-definidos no pacote STARDARD, mas o que é ainda mais interessante é que nós usuários também podemos definir os nossos próprios subtipos na PL/SQL. Vejamos na Listagem 10 como seria a sua criação:

Listagem 10. Criação de um subtipo de dados.

DECLARE 
  SUBTYPE nome_complero IS varchar2(60);
  SUBTYPE mensagem IS varchar2(100);
  msg mensagem;
  saudacao nome_completo;
  BEGIN
  saudacao := ‘Edson Dionisio’;
  msg := ‘Seja bem vindo ao ensinamento de subtipos
    definidos por usuários comuns.’;
  dbms_output.put_line(saudacao || ‘ ‘ || msg); 
  END;  
  /

Este é um simples exemplo do que podemos realizar através de subtipos na PL/SQL, basta apenas nos atentarmos aos tipos de informações que desejamos passar.

Valores NULL no PL/SQL

Na PL/SQL, valores null são como valores perdidos ou dados desconhecidos, que não são valores inteiros ou de nenhum outro tipo de dado especifico. Entendam que quando um valor é null, não estamos dizendo que isso implique que ele é um valor vazio ou 0. Null quer dizer realmente que não existe valor definido para determinado campo.

Com isso finalizamos este artigo, dando uma breve introdução ao mundo PL/SQL. Vimos como é trabalhar com os placeholders Variables (variáveis) e Constants (Constantes) no PL/SQL. Além disso, pudemos avaliar os tipos de dados existentes na PL/SQL, suas definições e variadas informações que nos são oferecidas.

Até a próxima!