Wie deklariere ich eine Variable und verwende sie im selben Oracle SQL-Skript?

133

Ich möchte wiederverwendbaren Code schreiben und muss zu Beginn einige Variablen deklarieren und im Skript wiederverwenden, z.

DEFINE stupidvar = 'stupidvarcontent';

SELECT stupiddata
FROM stupidtable
WHERE stupidcolumn = &stupidvar;

Wie kann ich eine Variable deklarieren und in folgenden Anweisungen wiederverwenden, z. B. bei der Verwendung von SQLDeveloper?


Versuche

  • Verwenden Sie einen DECLARE-Abschnitt und fügen Sie die folgende SELECT-Anweisung in BEGINund ein END;. Zugriff auf die Variable mit &stupidvar.
  • Verwenden Sie das Schlüsselwort DEFINEund greifen Sie auf die Variable zu.
  • Verwenden Sie das Schlüsselwort VARIABLEund greifen Sie auf die Variable zu.

Bei meinen Versuchen werden jedoch alle Arten von Fehlern angezeigt (Ungebundene Variable, Syntaxfehler, Erwartet SELECT INTO...).

bl4ckb0l7
quelle
2
Beachten Sie, dass der Ansatz in der akzeptierten Antwort von @APC ohne PL / SQL verwendet werden kann, z. B. in einem SQL Developer-Arbeitsblatt gemäß Ihrer Frage. Deklarieren Sie einfach die Variable in einer Zeile (kein Semikolon), dann die exec-Zeile, um ihren Wert festzulegen (Ende mit Semikolon), und dann Ihre select-Anweisung. Führen Sie es schließlich als Skript (F5) und nicht als Anweisung (F9) aus.
Amos M. Carpenter

Antworten:

139

Es gibt verschiedene Möglichkeiten, Variablen in SQL * Plus-Skripten zu deklarieren.

Die erste besteht darin, VAR zu verwenden, um eine Bindungsvariable zu deklarieren. Der Mechanismus zum Zuweisen von Werten zu einem VAR erfolgt mit einem EXEC-Aufruf:

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>

Ein VAR ist besonders nützlich, wenn wir eine gespeicherte Prozedur mit OUT-Parametern oder einer Funktion aufrufen möchten.

Alternativ können wir Substitutionsvariablen verwenden. Diese sind gut für den interaktiven Modus:

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>

Wenn wir ein Skript schreiben, das andere Skripte aufruft, kann es nützlich sein, die Variablen im Voraus zu definieren. Dieses Snippet wird ausgeführt, ohne dass ich aufgefordert werde, einen Wert einzugeben:

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>

Schließlich gibt es den anonymen PL / SQL-Block. Wie Sie sehen, können wir deklarierten Variablen weiterhin interaktiv Werte zuweisen:

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
quelle
6
Alles gut, außer dass Sie den Begriff "Bindungsvariable" verwenden. Die VAR-Deklaration erstellt eine Bindungsvariable, während ACCEPT oder DEFINE eine Substitutionsvariable erstellt.
Dave Costa
1
Ist es möglich, Variablen + Strings zu verketten?
Ecropolis
@Ecropolis - Ja, in SQL Plus wird standardmäßig der Zeitraum verwendet. Verwenden Sie SET CONCAT, um das Zeichen zu definieren, das den Namen einer Substitutionsvariablen von alphanumerischen Zeichen trennt, die unmittelbar auf den Variablennamen folgen. Verwenden Sie in PL / SQL oder SQL Double Pipe || zu verketten.
Laszlo Lugosi
Wenn SQL eine Standardsprache ist, warum ist es dann so schwierig, eine kanonische Referenz zu finden, die einfach überall funktioniert? WTF ???
Jww
1
@jww - SQL ist ein Standard, gibt jedoch nicht immer die genaue Syntax an, sodass verschiedene RDBMS-Produkte die Dinge unterschiedlich implementieren können. Datumsarithmetik ist ein gutes Beispiel. Auch die älteren Datenbankprodukte wie Oracle haben häufig Funktionen eingeführt, bevor der Standard sie abdeckte: zum Beispiel die hierarchische CONNECT BY-Syntax. In diesem Fall handelt es sich jedoch um SQL * Plus, ein Client-Tool, das ohnehin nicht vom ANSI-Standard abgedeckt wird.
APC
28

Versuchen Sie es mit doppelten Anführungszeichen, wenn es sich um eine char-Variable handelt:

DEFINE stupidvar = "'stupidvarcontent'";

oder

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
quelle
Vielen Dank für Ihre Antwort, aber wenn ich die Variable in doppelte Anführungszeichen setze, erhalte ich eine ORA-01008: not all variables bound.
bl4ckb0l7
1
Sicher! DEFINE num = 1; SELECT &num FROM dual;führt zu: ORA-01008: not all variables bound
bl4ckb0l7
@ bl4ckb0l7 - Ich wette, Sie versuchen dies nicht in SQL * Plus.
Laszlo Lugosi
20

In PL / SQL v.10

Das Schlüsselwort deklarieren wird verwendet, um eine Variable zu deklarieren

DECLARE stupidvar varchar(20);

Um einen Wert zuzuweisen, können Sie ihn bei der Deklaration festlegen

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

oder um etwas in diese Variable auszuwählen, verwenden Sie die INTOAnweisung. Sie müssen jedoch die Anweisung einschließen BEGINund ENDaußerdem sicherstellen, dass nur ein einzelner Wert zurückgegeben wird, und Semikolons nicht vergessen.

Die vollständige Erklärung würde also wie folgt lauten:

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

Ihre Variable ist nur verwendbar innerhalb BEGINund ENDso , wenn Sie mehr verwenden möchten , als werden Sie mehrere tun müssen BEGIN ENDUmhüllungen

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;

Hoffe das spart dir etwas Zeit

Matas Vaitkevicius
quelle
7

Wenn Sie das Datum deklarieren und dann in SQL Developer verwenden möchten.

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

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

Ich möchte nur Matas 'Antwort hinzufügen . Vielleicht ist es offensichtlich, aber ich habe lange gesucht, um herauszufinden, dass auf die Variable nur innerhalb der BEGIN-END- Konstruktion zugegriffen werden kann. Wenn Sie sie also später in einem Code verwenden müssen, müssen Sie diesen Code in BEGIN einfügen -END Block .

Beachten Sie, dass diese Blöcke verschachtelt werden können :

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
quelle
5

Die Frage, ob eine Variable in einem Skript verwendet werden soll, bedeutet für mich, dass sie in SQL * Plus verwendet wird.

Das Problem ist, dass Sie die Anführungszeichen verpasst haben und Oracle den Wert nicht in Zahlen analysieren kann.

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

Dieses Beispiel funktioniert aufgrund der automatischen Typkonvertierung (oder wie auch immer es heißt) einwandfrei.

Wenn Sie dies durch Eingabe von DEFINE in SQL * Plus überprüfen, wird angezeigt, dass die Variable num CHAR ist.

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

In diesem Fall ist dies kein Problem, da Oracle das Parsen von Zeichenfolgen in Zahlen verarbeiten kann, wenn es sich um eine gültige Zahl handelt.

Wenn die Zeichenfolge nicht nach Zahlen analysiert werden kann, kann Oracle nicht damit umgehen.

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

Wenn Sie also ein Zitat verwenden und Oracle nicht zwingen, es nach Zahlen zu analysieren, ist dies in Ordnung:

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

Um die ursprüngliche Frage zu beantworten, sollte es wie folgt aussehen:

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

Es gibt eine andere Möglichkeit, Variablen in SQL * Plus mithilfe des Abfragespaltenwerts zu speichern .

Die COL [UMN] verfügt über die Option new_value , um den Wert der Abfrage nach Feldnamen zu speichern.

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;

Wie Sie sehen können, wurde der X.log-Wert in die Variable dumm_var gesetzt , sodass wir feststellen können, dass eine X.log-Datei im aktuellen Verzeichnis ein Protokoll enthält.

Laszlo Lugosi
quelle
2

Hier ist deine Antwort:

DEFINE num := 1;       -- The semi-colon is needed for default values.
SELECT &num FROM dual;
stephen meckstroth
quelle
1
Ich auch. Ich benutze ODT und starte: DEFINE num: = 1; SELECT num FROM dual; Und was ich bekomme ist: ORA-00904: "NUM": ungültige Kennung 00904. 00000 - "% s: ungültige Kennung" * Ursache: * Aktion: Fehler in Zeile: 2 Spalte: 8
toha
0

In Toad verwende ich diese Arbeiten:

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;

Dann wird der Wert in das DBMS OutputFenster gedruckt .

Verweis auf hier und hier2 .

Yu Yang Jian
quelle
0

Manchmal müssen Sie eine Makrovariable verwenden, ohne den Benutzer zur Eingabe eines Werts aufzufordern. Meistens muss dies mit optionalen Skriptparametern erfolgen. Der folgende Code ist voll funktionsfähig

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

Ein ähnlicher Code wurde irgendwie im Verzeichnis rdbms / sql gefunden.

user12273401
quelle
0

Ein möglicher Ansatz, wenn Sie einen Parameter nur einmal angeben und an mehreren Stellen replizieren müssen, besteht darin, Folgendes zu tun:

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

Dieser Code generiert eine Zeichenfolge mit 8 zufälligen Ziffern.

Beachten Sie, dass ich eine Art Alias ​​mit dem Namen erstelle str_size, der die Konstante enthält 8. Es ist vernetzt, um mehr als einmal in der Abfrage verwendet zu werden.

Diego Queiroz
quelle