Essa é a questão.
Um post recente nos fóruns da OTN perguntou sobre o uso de ponto e vírgula e barras como terminadores de declaração. Tirei a poeira de um artigo que escrevi para nossa equipe de desenvolvimento há mais de 4 anos sobre esse tópico. Este artigo recebeu boas críticas e está disponível nos fóruns da OTN, se desejado. Pensei em postar também no meu blog. Aqui está o artigo:
Barra ou sem barra
por Brian Peasland
Em nossa empresa, os scripts SQL implantados são executados no utilitário de linha de comando SQL*Plus da Oracle, enquanto muitos desenvolvedores usam uma ferramenta GUI como PL/SQL Developer ou SQL Developer. A barra significa algo para o SQL*Plus que não é necessário no PL/SQL Developer ou no SQL Developer. Como tal, pode ser confuso saber se você precisa incluir uma barra em seus scripts SQL ou não. Esperançosamente, esta seção irá esclarecer o que a barra faz, quando usá-la e quando não usá-la. Terminador de ponto e vírgula Para a maioria das instruções SQL, o ponto e vírgula é o terminador de instrução. Por exemplo, considere esta simples instrução SQL executada no SQL*Plus:
SQL> selecione sysdate de dual;
SYSDATE
———
18-JUN-12
Quando o SQL*Plus vê o ponto e vírgula, ele sabe que o final da instrução SQL foi atingido e agora pode executar o comando.
Buffer SQL*Plus
Você pode não estar ciente de que o SQL*Plus possui um buffer para seus comandos. Se eu pressionar a tecla 'l' para 'lista', posso ver o comando atualmente no buffer da minha sessão.
SQL>l
1 * selecione sysdate de dual
Não surpreendentemente, há o comando que acabei de executar. Em seguida, executei outra instrução SQL e aqui está a aparência do meu buffer:
SQL>l
1 selecione sysdate, usuário
2* de duplo
Como você pode ver, agora tenho duas linhas no buffer SQL*Plus da minha sessão.
Barra =Executar buffer
A primeira regra a entender sobre a barra é que para o SQL*Plus, a barra significa executar o conteúdo do buffer. Para ilustrar esse conceito, executarei uma instrução SQL, aguardarei alguns segundos e, em seguida, executarei a mesma instrução SQL novamente, mas apenas executando o buffer.
SQL> selecione to_char(sysdate,'MM/DD/AAAA HH24:MI:SS') de dual;
TO_CHAR(SYSDATE,'MM
——————-
18/06/2012 15:20:40
SQL> /
TO_CHAR(SYSDATE,'MM
——————-
18/06/2012 15:21:17
SQL> /
TO_CHAR(SYSDATE,'MM
——————-
18/06/2012 15:21:50
Você pode ver que tudo o que fiz na segunda e na terceira vez foi apenas digitar '/' e pressionar enter e o SQL*Plus executou o conteúdo de seu buffer de comando a cada vez.
Blocos PL/SQL
O terminador de instrução de ponto e vírgula funcionou bem sozinho até que a Oracle introduziu o PL/SQL no Oracle versão 7. O problema é que os blocos PL/SQL podem ter vários pontos e vírgulas para encerrar as instruções individuais que compõem esse bloco. Considere este bloco PL/SQL muito simples que não faz nada:
SQL> iniciar
2 nulo;
3 nulo;
4 fim;
5
As linhas 2 e 3 contêm instruções perfeitamente válidas, cada uma terminada com ponto e vírgula. E na linha 4, temos a palavra-chave END significando o fim do bloco PL/SQL. Se não for permitido pares BEGIN/END aninhados, toda vez que o SQL*Plus vir “END;” ele saberia que o fim do bloco PL/SQL foi atingido, mas nos são permitidos pares BEGIN/END aninhados, então o seguinte é perfeitamente legal e válido:
SQL> iniciar
2 começar
3 nulo;
4 fim;
5 nulo;
6 fim;
7
Você pode dizer acima que apenas procurando por “END;” não é suficiente porque o SQL*Plus teria tentado executar o bloco após a linha 4. Então, como a Oracle decidiu indicar que o bloco PL/SQL estava pronto para ser executado? A resposta é usando a barra, como você já deve estar ciente. A segunda regra a entender é que tudo que a barra está fazendo quando você a usa para finalizar um bloco PL/SQL é dizer ao SQL*Plus para executar o que está no buffer! Isso não mudou desde antes da criação do PL/SQL para o Oracle 7. Considere o seguinte exemplo:
SQL> iniciar
2 nulo;
3 fim;
4 /
Procedimento PL/SQL concluído com sucesso.
SQL>l
1 início
2 nulo;
3* fim;
Na linha 4, digitei a barra para executar o bloco PL/SQL. Você pode ver que meu bloco foi concluído com sucesso. Se voltarmos e olharmos para o conteúdo do meu buffer de comando, você verá que ele contém tudo, menos a barra. A barra não faz parte do buffer de comando. Então agora, vou executar um bloco PL/SQL diferente:
SQL> iniciar
2 dbms_output.put_line('Hoje é '||to_char(sysdate,'MM/DD/AAAA HH24:MI:SS'));
3 fim;
4 /
Hoje é 18/06/2012 15:39:32
Procedimento PL/SQL concluído com sucesso.
A barra disse ao SQL*Plus para executar o que está em seu buffer e os resultados são exibidos. Agora vamos digitar apenas a barra novamente e devemos ver nosso bloco PL/SQL sendo executado novamente.
SQL> /
Hoje é 18/06/2012 15:40:42
Procedimento PL/SQL concluído com sucesso.
Não precisei digitar meu bloco PL/SQL novamente, pois ele está atualmente no buffer de comando.
Desenvolvedor PL/SQL e SQL e Blocos PL/SQL
O maior problema para a maioria dos desenvolvedores é que o PL/SQL Developer e o SQL Developer não exigem que você use a barra. Por quê? Porque você pode clicar em Executar (F8) ou Executar Script (F5) para executar seu bloco PL/SQL. O PL/SQL Developer sabe que no momento em que você pressionar F8, você pretende enviar o bloco PL/SQL para ser executado. Nesse caso, F8 no PL/SQL Developer está fazendo o mesmo trabalho que a barra no SQL*Plus. Da mesma forma, para F5 no SQL Developer.
O problema na minha empresa é que nossa equipe de implantação de código para produção não implanta código com PL/SQL Developer ou SQL Developer. Eles usam o SQL*Plus porque criar scripts de várias execuções é mais fácil com uma ferramenta de linha de comando. Muitos desenvolvedores cometem o erro de não incluir a barra para blocos PL/SQL em scripts porque eles não precisam dela, mas se você deseja implantar essa seção de código em um script SQL, a barra é necessária no final de cada PL bloco /SQL.
Quando não usar barra
Então, vimos quando e por que usamos a barra, mas quando é ruim usá-la? A terceira regra a saber é que é ruim usar a barra após uma única instrução SQL (não em um bloco PL/SQL), especialmente quando essa barra segue imediatamente uma instrução DML (INSERT, UPDATE ou DELETE). Se meu script contiver o seguinte:
selecione sysdate de dual;
/
Então, obterei “saída dupla”, que não é o que normalmente pretendo fazer em um script. Eu realmente quero apenas uma linha retornada, não duas, como o script acima faria:
SQL> selecione sysdate de dual;
SYSDATE
———
18-JUN-12
SQL> /
SYSDATE
———
18-JUN-12
É ainda pior quando eu uso a barra após uma instrução DML porque essa instrução será executada duas vezes. Considere o seguinte roteiro:
insira em valores test_tab (10);
/
Agora sabemos que quando executo as duas linhas acima em um script, o SQL*Plus o executará uma vez devido ao terminador de instrução de ponto e vírgula e, em seguida, executará uma segunda vez porque a barra indica ao SQL*Plus para executar o que está no buffer de comando. Quando executo o script de duas linhas acima, recebo a seguinte saída:
SQL> insira nos valores test_tab (10);
1 linha criada.
SQL>
/
insira em valores test_tab (10) *
ERRO na linha 1:ORA-00001:restrição exclusiva (PEASLAND.SYS_C00767176) violada
Ops! A primeira inserção funcionou (criada 1 linha), mas quando a barra foi inserida, o SQL*Plus tentou inserir os mesmos dados e fui pego em uma violação de restrição exclusiva.
Conclusão
Felizmente, esta página mostra por que a barra é necessária, o que ela faz e quando não usá-la. Para recapitular:
- Inclua a barra no final de cada bloco PL/SQL
- Não inclua a barra após nenhuma instrução SQL que não esteja em um bloco PL/SQL.
- A barra após uma única instrução SQL fará com que o comando SQL seja executado duas vezes.