Jak zadeklarować zmienną i użyć jej w tym samym skrypcie Oracle SQL?

135

Chcę napisać kod wielokrotnego użytku i muszę na początku zadeklarować niektóre zmienne i użyć ich ponownie w skrypcie, takich jak:

DEFINE stupidvar = 'stupidvarcontent';

SELECT stupiddata
FROM stupidtable
WHERE stupidcolumn = &stupidvar;

Jak mogę zadeklarować zmienną i ponownie użyć jej w instrukcjach, które następują, na przykład przy użyciu SQLDeveloper.


Próbowanie

  • Użyj sekcji DECLARE i wstaw następującą instrukcję SELECT w BEGINi END;. Dostęp do zmiennej za pomocą &stupidvar.
  • Użyj słowa kluczowego DEFINEi uzyskaj dostęp do zmiennej.
  • Użycie słowa kluczowego VARIABLEi dostęp do zmiennej.

Ale otrzymuję wszelkiego rodzaju błędy podczas moich prób (zmienna niezwiązana, błąd składni, oczekiwano SELECT INTO...).

bl4ckb0l7
źródło
2
Zwróć uwagę, że podejście w zaakceptowanej odpowiedzi @APC może być użyte bez PL / SQL, np. W arkuszu SQL Developer zgodnie z twoim pytaniem. Po prostu zadeklaruj zmienną w jednym wierszu (bez średnika), następnie w wierszu exec, aby ustawić jej wartość (zakończ średnikiem), a następnie wybierz instrukcję. Na koniec uruchom go jako skrypt (F5), a nie jako instrukcję (F9).
Amos M. Carpenter,

Odpowiedzi:

139

Istnieje kilka sposobów deklarowania zmiennych w skryptach SQL * Plus.

Pierwszym jest użycie funkcji WARIANCJA, aby zadeklarować zmienną powiązania. Mechanizm przypisywania wartości do VAR polega na wywołaniu 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>

WARIANCJA jest szczególnie przydatna, gdy chcemy wywołać procedurę składowaną, która ma parametry OUT lub funkcję.

Alternatywnie możemy użyć zmiennych substytucyjnych. Są dobre w trybie interaktywnym:

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>

Kiedy piszemy skrypt, który wywołuje inne skrypty, przydatne może być zdefiniowanie zmiennych z góry. Ten fragment kodu działa bez monitowania o wprowadzenie wartości:

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>

Wreszcie jest anonimowy blok PL / SQL. Jak widzisz, nadal możemy przypisywać wartości do zadeklarowanych zmiennych w sposób interaktywny:

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
źródło
6
Wszystko dobrze, z wyjątkiem twojego użycia terminu „zmienna wiążąca”. Deklaracja VAR tworzy zmienną wiążącą, podczas gdy ACCEPT lub DEFINE tworzy zmienną zastępczą.
Dave Costa,
1
Czy można łączyć zmienne + ciągi?
Ecropolis
@Ecropolis - tak, w SQL Plus okres użytkowania domyślnie. Użyj polecenia SET CONCAT, aby zdefiniować znak oddzielający nazwę zmiennej podstawiania od znaków alfanumerycznych występujących bezpośrednio po nazwie zmiennej. W PL / SQL lub SQL użyj podwójnej kreski || do konkatenacji.
Laszlo Lugosi
1
Jeśli SQL jest językiem standardowym, dlaczego tak trudno jest znaleźć odwołanie kanoniczne, które działa wszędzie? WTF ???
jww
1
@jww - SQL jest standardem, ale nie zawsze określa dokładną składnię, więc różne produkty RDBMS mogą implementować różne rzeczy; Dobrym przykładem jest arytmetyka dat. Również starsze produkty bazodanowe, takie jak Oracle, często wprowadzały funkcje, zanim objęły je Standard: na przykład hierarchiczna składnia CONNECT BY. Ale w tym przypadku omawiamy SQL * Plus, który jest narzędziem klienckim, a więc i tak nie jest objęty standardem ANSI.
APC
30

Spróbuj użyć cudzysłowów, jeśli jest to zmienna typu char:

DEFINE stupidvar = "'stupidvarcontent'";

lub

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
źródło
Dziękuję za odpowiedź, ale jeśli umieszczę zmienną w podwójnych cudzysłowach, otrzymam ORA-01008: not all variables bound.
bl4ckb0l7
1
Pewnie! DEFINE num = 1; SELECT &num FROM dual;prowadzi do: ORA-01008: not all variables bound
bl4ckb0l7
@ bl4ckb0l7 - Założę się, że próbujesz tego nie w SQL * Plus.
Laszlo Lugosi,
Ta odpowiedź ratuje życie! Często używałem DEFINE podczas pisania raportów i nigdy nie miałem problemu. W ważnym projekcie otrzymywałem błędy i mogłem powiedzieć, że to dlatego, że zmienna została przekazana jako liczba zamiast wartości ciągu. Dzięki!!
SherlockSpreadsheets
21

W PL / SQL v.10

słowo kluczowe deklarujemy służy do deklarowania zmiennej

DECLARE stupidvar varchar(20);

aby przypisać wartość, możesz ją ustawić podczas deklaracji

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

lub aby wybrać coś w tej zmiennej, której używasz INTOinstrukcji, jednak musisz zawinąć instrukcję, BEGINa ENDtakże musisz upewnić się, że zwracana jest tylko pojedyncza wartość i nie zapomnij o średnikach.

więc pełne oświadczenie wyglądałoby następująco:

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

Zmienna jest użyteczny tylko w ciągu BEGINa ENDwięc jeśli chcesz używać więcej niż jednego trzeba będzie zrobić wiele BEGIN ENDopakowań

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;

Mam nadzieję, że zaoszczędzi ci to trochę czasu

Matas Vaitkevicius
źródło
7

Jeśli chcesz zadeklarować datę, a następnie użyj jej w SQL Developer.

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

SELECT * 
FROM proposal 
WHERE prop_start_dt = &PROPp_START_DT
SVK
źródło
5

Pytanie dotyczy użycia zmiennej w skrypcie oznacza, że ​​dla mnie będzie ona używana w SQL * Plus.

Problem polega na tym, że przegapiłeś cudzysłowy, a Oracle nie może przeanalizować wartości na liczbę.

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

Ten przykład działa dobrze z powodu automatycznej konwersji typu (lub jakkolwiek to się nazywa).

Jeśli zaznaczysz wpisując DEFINE w SQL * Plus, pokaże się, że zmienną num jest CHAR.

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

W tym przypadku nie stanowi to problemu, ponieważ Oracle może zająć się przetwarzaniem ciągu znaków na liczbę, jeśli byłaby to poprawna liczba.

Kiedy ciąg nie może przeanalizować liczby, Oracle nie może sobie z nim poradzić.

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

Z cytatem, więc nie zmuszaj Oracle do analizowania liczb, będzie dobrze:

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

Tak więc, aby odpowiedzieć na pierwotne pytanie, należy wykonać tę próbkę:

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

Istnieje inny sposób przechowywania zmiennych w SQL * Plus przy użyciu wartości kolumny zapytania .

COL [UMN] ma new_value opcję do przechowywania wartości z kwerendy przy nazwie pola.

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;

Jak widać, wartość X.log została ustawiona w zmiennej stupid_var , więc możemy znaleźć plik X.log w bieżącym katalogu, w którym jest jakiś dziennik.

Laszlo Lugosi
źródło
5

Chcę tylko dodać odpowiedź Matasa . Może to oczywiste, ale długo szukałem, aby dowiedzieć się, że zmienna jest dostępna tylko w konstrukcji BEGIN-END , więc jeśli będziesz musiał użyć jej później w jakimś kodzie, musisz umieścić ten kod wewnątrz BEGIN -END blok .

Zwróć uwagę, że te bloki mogą być zagnieżdżane :

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
źródło
2

Oto twoja odpowiedź:

DEFINE num := 1;       -- The semi-colon is needed for default values.
SELECT &num FROM dual;
Stephen Meckstroth
źródło
1
To samo u mnie. Używam ODT i uruchamiam: DEFINE num: = 1; SELECT num FROM dual; Otrzymuję: ORA-00904: „NUM”: nieprawidłowy identyfikator 00904. 00000 - „% s: nieprawidłowy identyfikator” * Przyczyna: * Akcja: Błąd w wierszu: 2 Kolumna: 8
toha
1

W Toad używam tego działa:

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;

Następnie wartość zostanie wydrukowana w DBMS Outputoknie.

Odniesienie do tutaj i tutaj 2 .

yu yang Jian
źródło
0

Czasami trzeba użyć makrozmiennej bez pytania użytkownika o wprowadzenie wartości. Najczęściej trzeba to zrobić z opcjonalnymi parametrami skryptu. Poniższy kod jest w pełni funkcjonalny

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

Podobny kod został w jakiś sposób znaleziony w katalogu rdbms / sql.

user12273401
źródło
0

Jednym z możliwych rozwiązań, jeśli potrzebujesz tylko raz określić parametr i powielić go w kilku miejscach, jest zrobienie czegoś takiego:

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 */

Ten kod generuje ciąg 8 losowych cyfr.

Zauważ, że tworzę rodzaj aliasu o nazwie, str_sizektóry przechowuje stałą 8. Jest łączony krzyżowo, aby mógł być używany więcej niż raz w zapytaniu.

Diego Queiroz
źródło