Como declarar variável e usá-lo no mesmo script Oracle SQL?

133

Quero escrever código reutilizável e preciso declarar algumas variáveis ​​no início e reutilizá-las no script, como:

DEFINE stupidvar = 'stupidvarcontent';

SELECT stupiddata
FROM stupidtable
WHERE stupidcolumn = &stupidvar;

Como posso declarar uma variável e reutilizá-la em instruções a seguir, como em usá-la SQLDeveloper.


Tentativas

  • Use uma seção DECLARE e insira a seguinte instrução SELECT em BEGINe END;. Acessa a variável usando &stupidvar.
  • Use a palavra-chave DEFINEe acesse a variável
  • Usando a palavra-chave VARIABLEe acesse a variável

Mas estou recebendo todos os tipos de erros durante minhas tentativas (variável não vinculada, erro de sintaxe, esperado SELECT INTO...).

bl4ckb0l7
fonte
2
Observe que a abordagem na resposta aceita pelo @APC pode ser usada sem o PL / SQL, por exemplo, em uma planilha do SQL Developer conforme sua pergunta. Apenas declare a variável em uma linha (sem ponto e vírgula), depois a linha exec para definir seu valor (finalize com ponto e vírgula) e, em seguida, sua instrução select. Por fim, execute-o como um script (F5), não como uma instrução (F9).
Amos M. Carpenter

Respostas:

139

Existem várias maneiras de declarar variáveis ​​nos scripts SQL * Plus.

O primeiro é usar VAR, para declarar uma variável de ligação. O mecanismo para atribuir valores a um VAR é com uma chamada EXEC:

SQL> var name varchar2(20)
SQL> exec :name := 'SALES'

PL/SQL procedure successfully completed.

SQL> select * from dept
  2  where dname = :name
  3  /

    DEPTNO DNAME          LOC
---------- -------------- -------------
        30 SALES          CHICAGO

SQL>

Um VAR é particularmente útil quando queremos chamar um procedimento armazenado que possua parâmetros ou função OUT.

Como alternativa, podemos usar variáveis ​​de substituição. Estes são bons para o modo interativo:

SQL> accept p_dno prompt "Please enter Department number: " default 10
Please enter Department number: 20
SQL> select ename, sal
  2  from emp
  3  where deptno = &p_dno
  4  /
old   3: where deptno = &p_dno
new   3: where deptno = 20

ENAME             SAL
---------- ----------
CLARKE            800
ROBERTSON        2975
RIGBY            3000
KULASH           1100
GASPAROTTO       3000

SQL>

Quando estamos escrevendo um script que chama outros scripts, pode ser útil DEFINIR as variáveis ​​antecipadamente. Este snippet é executado sem solicitar que eu insira um valor:

SQL> def p_dno = 40
SQL> select ename, sal
  2  from emp
  3  where deptno = &p_dno
  4  /
old   3: where deptno = &p_dno
new   3: where deptno = 40

no rows selected

SQL>

Finalmente, há o bloco PL / SQL anônimo. Como você vê, ainda podemos atribuir valores a variáveis ​​declaradas interativamente:

SQL> set serveroutput on size unlimited
SQL> declare
  2      n pls_integer;
  3      l_sal number := 3500;
  4      l_dno number := &dno;
  5  begin
  6      select count(*)
  7      into n
  8      from emp
  9      where sal > l_sal
 10      and deptno = l_dno;
 11      dbms_output.put_line('top earners = '||to_char(n));
 12  end;
 13  /
Enter value for dno: 10
old   4:     l_dno number := &dno;
new   4:     l_dno number := 10;
top earners = 1

PL/SQL procedure successfully completed.

SQL>
APC
fonte
6
Tudo bem, exceto pelo uso do termo "variável de ligação". A declaração VAR cria uma variável de ligação, enquanto ACCEPT ou DEFINE cria uma variável de substituição.
Dave Costa
1
É possível concatenar variáveis ​​+ strings?
Ecropolis
@Ecropolis - sim, no SQL Plus, use o período por padrão. Use SET CONCAT para definir o caractere que separa o nome de uma variável de substituição dos caracteres alfanuméricos que seguem imediatamente o nome da variável. No PL / SQL ou SQL, use double pipe || concatenar.
Laszlo Lugosi
Se SQL é uma linguagem padrão, por que é tão difícil encontrar uma referência canônica que funcione em todos os lugares? WTF ???
JWW
1
@jww - SQL é um padrão, mas nem sempre especifica a sintaxe exata para que diferentes produtos RDBMS possam implementar as coisas de maneira diferente; data aritmética é um bom exemplo. Além disso, produtos de banco de dados mais antigos, como a Oracle, costumavam apresentar recursos antes que o Standard os cobrisse: por exemplo, a sintaxe hierárquica CONNECT BY. Mas, neste caso, estamos discutindo o SQL * Plus, que é uma ferramenta cliente e, portanto, não é coberta pelo padrão ANSI.
APC
28

Tente usar aspas duplas se for uma variável char:

DEFINE stupidvar = "'stupidvarcontent'";

ou

DEFINE stupidvar = 'stupidvarcontent';

SELECT stupiddata  
FROM stupidtable  
WHERE stupidcolumn = '&stupidvar'

upd:

SQL*Plus: Release 10.2.0.1.0 - Production on Wed Aug 25 17:13:26 2010

Copyright (c) 1982, 2005, Oracle.  All rights reserved.

SQL> conn od/od@etalon
Connected.
SQL> define var = "'FL-208'";
SQL> select code from product where code = &var;
old   1: select code from product where code = &var
new   1: select code from product where code = 'FL-208'

CODE
---------------
FL-208

SQL> define var = 'FL-208';
SQL> select code from product where code = &var;
old   1: select code from product where code = &var
new   1: select code from product where code = FL-208
select code from product where code = FL-208
                                      *
ERROR at line 1:
ORA-06553: PLS-221: 'FL' is not a procedure or is undefined
Kirill Leontev
fonte
Obrigado pela resposta, mas se eu incluir o var entre aspas duplas, recebo a ORA-01008: not all variables bound.
Bl4ckb0l7
1
Certo! DEFINE num = 1; SELECT &num FROM dual;leva a: ORA-01008: not all variables bound
bl4ckb0l7
@ bl4ckb0l7 - Aposto que você está tentando isso não no SQL * Plus.
Laszlo Lugosi
20

No PL / SQL v.10

A palavra-chave declare é usada para declarar variável

DECLARE stupidvar varchar(20);

para atribuir um valor, você pode defini-lo quando declarar

DECLARE stupidvar varchar(20) := '12345678';

ou para selecionar algo nessa variável, você usa a INTOinstrução, no entanto, é necessário agrupar a instrução BEGINe END, também, garantir que apenas um valor único seja retornado e não se esqueça de ponto e vírgula.

então a declaração completa sairia a seguir:

DECLARE stupidvar varchar(20);
BEGIN
    SELECT stupid into stupidvar FROM stupiddata CC 
    WHERE stupidid = 2;
END;

Sua variável é utilizável apenas dentro de BEGIN e, ENDportanto, se você quiser usar mais de uma, precisará fazer vários BEGIN ENDinvólucros

DECLARE stupidvar varchar(20);
BEGIN
    SELECT stupid into stupidvar FROM stupiddata CC 
    WHERE stupidid = 2;

    DECLARE evenmorestupidvar varchar(20);
    BEGIN
        SELECT evenmorestupid into evenmorestupidvar FROM evenmorestupiddata CCC 
        WHERE evenmorestupidid = 42;

        INSERT INTO newstupiddata (newstupidcolumn, newevenmorestupidstupidcolumn)
        SELECT stupidvar, evenmorestupidvar 
        FROM dual

    END;
END;

Espero que isso economize algum tempo

Matas Vaitkevicius
fonte
7

Se você deseja declarar a data e usá-la no SQL Developer.

DEFINE PROPp_START_DT = TO_DATE('01-SEP-1999')

SELECT * 
FROM proposal 
WHERE prop_start_dt = &PROPp_START_DT
SVK
fonte
5

Só quero adicionar a resposta de Matas . Talvez seja óbvio, mas pesquisei por um longo tempo para descobrir que a variável está acessível apenas dentro da construção BEGIN-END ; portanto, se você precisar usá-la em algum código posteriormente, precisará inseri-lo no código BEGIN Bloco -END .

Observe que esses blocos podem ser aninhados :

DECLARE x NUMBER;
  BEGIN
    SELECT PK INTO x FROM table1 WHERE col1 = 'test';

    DECLARE y NUMBER;
    BEGIN
    SELECT PK INTO y FROM table2 WHERE col2 = x;

    INSERT INTO table2 (col1, col2)
      SELECT y,'text'
      FROM dual
      WHERE exists(SELECT * FROM table2);
    COMMIT;
  END;
END;
Katia Savina
fonte
5

A questão está prestes a usar uma variável em um script significa que, para mim, ela será usada no SQL * Plus.

O problema é que você perdeu as aspas e o Oracle não pode analisar o valor em número.

SQL> DEFINE num = 2018
SQL> SELECT &num AS your_num FROM dual;
old   1: SELECT &num AS your_num FROM dual
new   1: SELECT 2018 AS your_num FROM dual

  YOUR_NUM
----------
      2018

Elapsed: 00:00:00.01

Este exemplo funciona bem devido à conversão automática de tipo (ou como ele é chamado).

Se você verificar digitando DEFINE no SQL * Plus, isso mostrará que a variável num é CHAR.

SQL>define
DEFINE NUM             = "2018" (CHAR)

Não é um problema neste caso, porque o Oracle pode lidar com a análise de sequência de números, se for um número válido.

Quando a sequência não pode analisar o número, o Oracle não pode lidar com ela.

SQL> DEFINE num = 'Doh'
SQL> SELECT &num AS your_num FROM dual;
old   1: SELECT &num AS your_num FROM dual
new   1: SELECT Doh AS your_num FROM dual
SELECT Doh AS your_num FROM dual
       *
ERROR at line 1:
ORA-00904: "DOH": invalid identifier

Com uma cotação, portanto, não force o Oracle a analisar o número, tudo bem:

17:31:00 SQL> SELECT '&num' AS your_num FROM dual;
old   1: SELECT '&num' AS your_num FROM dual
new   1: SELECT 'Doh' AS your_num FROM dual

YOU
---
Doh

Portanto, para responder à pergunta original, faça o seguinte:

SQL> DEFINE stupidvar = 'X'
SQL>
SQL> SELECT 'print stupidvar:' || '&stupidvar'
  2  FROM dual
  3  WHERE dummy = '&stupidvar';
old   1: SELECT 'print stupidvar:' || '&stupidvar'
new   1: SELECT 'print stupidvar:' || 'X'
old   3: WHERE dummy = '&stupidvar'
new   3: WHERE dummy = 'X'

'PRINTSTUPIDVAR:'
-----------------
print stupidvar:X

Elapsed: 00:00:00.00

Há uma outra maneira de armazenar variáveis ​​no SQL * Plus usando Valor da Coluna de Consulta .

O COL [UMN] tem new_value opção para armazenar o valor da consulta pelo nome do campo.

SQL> COLUMN stupid_column_name new_value stupid_var noprint
SQL> SELECT dummy || '.log' AS stupid_column_name
  2  FROM dual;

Elapsed: 00:00:00.00
SQL> SPOOL &stupid_var.
SQL> SELECT '&stupid_var' FROM DUAL;
old   1: SELECT '&stupid_var' FROM DUAL
new   1: SELECT 'X.log' FROM DUAL

X.LOG
-----
X.log

Elapsed: 00:00:00.00
SQL>SPOOL OFF;

Como você pode ver, o valor X.log foi definido na variável stupid_var , para que possamos encontrar um arquivo X.log no diretório atual com algum log.

Laszlo Lugosi
fonte
2

Aqui está sua resposta:

DEFINE num := 1;       -- The semi-colon is needed for default values.
SELECT &num FROM dual;
stephen meckstroth
fonte
1
O mesmo comigo. Eu uso ODT e corro: DEFINE num: = 1; SELECT num FROM dual; E o que eu recebo é: ORA-00904: "NUM": identificador inválido 00904. 00000 - "% s: identificador inválido" * Causa: Ação *: erro na linha: 2 Coluna: 8
toha
0

No sapo eu uso este funciona:

declare 
    num number;
begin 
    ---- use 'select into' works 
    --select 123 into num from dual;

    ---- also can use :=
    num := 123;
    dbms_output.Put_line(num);
end;

Em seguida, o valor será impresso na DBMS Outputjanela.

Referência para aqui e aqui2 .

yu yang Jian
fonte
0

Às vezes, você precisa usar uma variável de macro sem solicitar ao usuário que insira um valor. Geralmente, isso precisa ser feito com parâmetros de script opcionais. O código a seguir é totalmente funcional

column 1 noprint new_value 1
select '' "1" from dual where 2!=2;
select nvl('&&1', 'VAH') "1" from dual;
column 1 clear
define 1

Código semelhante foi encontrado de alguma forma no diretório rdbms / sql.

user12273401
fonte
0

Uma abordagem possível, se você precisar especificar um parâmetro apenas uma vez e replicá-lo em vários locais, é fazer algo assim:

SELECT
  str_size  /* my variable usage */
  , LPAD(TRUNC(DBMS_RANDOM.VALUE * POWER(10, str_size)), str_size, '0') rand
FROM
  dual  /* or any other table, or mixed of joined tables */
  CROSS JOIN (SELECT 8 str_size FROM dual);  /* my variable declaration */

Este código gera uma sequência de 8 dígitos aleatórios.

Observe que eu crio um tipo de alias chamado str_sizeque mantém a constante 8. É junção cruzada para ser usada mais de uma vez na consulta.

Diego Queiroz
fonte