Làm thế nào để khai báo biến và sử dụng nó trong cùng một tập lệnh SQL của Oracle?


133

Tôi muốn viết mã có thể sử dụng lại và cần khai báo một số biến ở đầu và sử dụng lại chúng trong tập lệnh, chẳng hạn như:

DEFINE stupidvar = 'stupidvarcontent';

SELECT stupiddata
FROM stupidtable
WHERE stupidcolumn = &stupidvar;

Làm cách nào tôi có thể khai báo một biến và sử dụng lại nó trong các câu lệnh tiếp theo như sử dụng SQLDeveloper.


Nỗ lực

  • Sử dụng phần DECLARE và chèn câu lệnh CHỌN sau vào BEGINEND;. Tích lũy biến bằng cách sử dụng &stupidvar.
  • Sử dụng từ khóa DEFINEvà truy cập vào biến.
  • Sử dụng từ khóa VARIABLEvà truy cập vào biến.

Nhưng tôi đang nhận được tất cả các loại lỗi trong các lần thử của mình (Biến không liên kết, Lỗi cú pháp, Dự kiến SELECT INTO...).


2
Lưu ý rằng cách tiếp cận trong câu trả lời được chấp nhận bởi @APC có thể được sử dụng mà không cần PL / SQL, ví dụ: trong bảng tính Nhà phát triển SQL theo câu hỏi của bạn. Chỉ cần khai báo biến trên một dòng (không có dấu chấm phẩy), sau đó dòng exec để đặt giá trị của nó (kết thúc bằng dấu chấm phẩy), sau đó chọn câu lệnh của bạn. Cuối cùng, chạy nó dưới dạng tập lệnh (F5), không phải là câu lệnh (F9).
Amos M. Carpenter

Câu trả lời:


139

Có một số cách khai báo các biến trong các tập lệnh SQL * Plus.

Đầu tiên là sử dụng VAR, để khai báo một biến liên kết. Cơ chế gán giá trị cho VAR là với lệnh gọi 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>

VAR đặc biệt hữu ích khi chúng ta muốn gọi một thủ tục được lưu trữ có tham số OUT hoặc hàm.

Ngoài ra, chúng ta có thể sử dụng các biến thay thế. Đây là tốt cho chế độ tương tác:

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>

Khi chúng ta viết một tập lệnh gọi các tập lệnh khác, nó có thể hữu ích để xác định trước các biến. Đoạn mã này chạy mà không nhắc tôi nhập giá trị:

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>

Cuối cùng, có khối PL / SQL ẩn danh. Như bạn thấy, chúng ta vẫn có thể gán giá trị cho các biến được khai báo một cách tương tác:

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>

6
Tất cả đều tốt, ngoại trừ việc bạn sử dụng thuật ngữ "biến liên kết". Khai báo VAR tạo một biến liên kết, trong khi ACCEPT hoặc DEFINE tạo một biến thay thế.
Dave Costa

1
Có thể nối các biến + chuỗi không?
Đô thị

@Ecropolis - có, theo mặc định, thời gian sử dụng SQL Plus. Sử dụng SET CONCAT để xác định ký tự phân tách tên của biến thay thế với các ký tự chữ và số ngay sau tên biến. Trong PL / SQL hoặc SQL sử dụng ống đôi | | để nối.
Laszlo Lugosi

Nếu SQL là một ngôn ngữ tiêu chuẩn thì tại sao rất khó để tìm một tài liệu tham khảo chính tắc chỉ hoạt động ở mọi nơi? WTF ???
jww

1
@jww - SQL là một tiêu chuẩn nhưng không phải lúc nào cũng chỉ định cú pháp chính xác để các sản phẩm RDBMS khác nhau có thể triển khai mọi thứ khác nhau; số học ngày là ví dụ tốt. Ngoài ra, các sản phẩm cơ sở dữ liệu cũ hơn như Oracle thường giới thiệu các tính năng trước khi Tiêu chuẩn bao trùm chúng: ví dụ cú pháp CONNECT BY phân cấp. Nhưng trong trường hợp này, chúng tôi đang thảo luận về SQL * Plus, đây là một công cụ máy khách và do đó không được bao phủ bởi tiêu chuẩn ANSI.
APC

28

Hãy thử sử dụng dấu ngoặc kép nếu đó là biến char:

DEFINE stupidvar = "'stupidvarcontent'";

hoặc là

DEFINE stupidvar = 'stupidvarcontent';

SELECT stupiddata  
FROM stupidtable  
WHERE stupidcolumn = '&stupidvar'

cập nhật:

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

Cảm ơn câu trả lời của bạn, nhưng nếu tôi bao gồm var trong dấu ngoặc kép, tôi nhận được a ORA-01008: not all variables bound.
bl4ckb0l7

1
Chắc chắn rồi! DEFINE num = 1; SELECT &num FROM dual;dẫn đến: ORA-01008: not all variables bound
bl4ckb0l7

@ bl4ckb0l7 - Tôi cá là bạn đang thử cái này không phải trong SQL * Plus.
Laszlo Lugosi

20

Trong PL / SQL v.10

khai báo từ khóa được sử dụng để khai báo biến

DECLARE stupidvar varchar(20);

để gán một giá trị bạn có thể đặt nó khi bạn khai báo

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

hoặc để chọn một cái gì đó vào biến đó bạn sử dụng INTOcâu lệnh, tuy nhiên bạn cần phải bọc câu lệnh trong BEGINEND , bạn cũng cần đảm bảo rằng chỉ có một giá trị duy nhất được trả về và đừng quên dấu chấm phẩy.

vì vậy, tuyên bố đầy đủ sẽ được đưa ra như sau:

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

Biến của bạn chỉ có thể sử dụng được bên trong BEGINENDvì vậy nếu bạn muốn sử dụng nhiều hơn một, bạn sẽ phải thực hiện nhiều BEGIN ENDkết thúc

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;

Hy vọng điều này sẽ giúp bạn tiết kiệm thời gian


7

Nếu bạn muốn khai báo ngày và sau đó sử dụng nó trong SQL Developer.

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

SELECT * 
FROM proposal 
WHERE prop_start_dt = &PROPp_START_DT

5

Chỉ muốn thêm câu trả lời của Matas . Có thể đó là điều hiển nhiên, nhưng tôi đã tìm kiếm trong một thời gian dài để tìm ra rằng biến chỉ có thể truy cập được trong cấu trúc BEGIN-END , vì vậy nếu bạn cần sử dụng nó trong một số mã sau, bạn cần đặt mã này vào BEGIN Khối -END .

Lưu ý rằng các khối này có thể được lồng nhau :

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;

5

Câu hỏi là về việc sử dụng một biến trong tập lệnh có nghĩa là nó sẽ được sử dụng trong SQL * Plus.

Vấn đề là bạn đã bỏ lỡ các trích dẫn và Oracle không thể phân tích giá trị thành số.

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

Mẫu này hoạt động tốt vì chuyển đổi loại tự động (hoặc bất cứ thứ gì nó được gọi).

Nếu bạn kiểm tra bằng cách nhập DEFINE trong SQL * Plus, nó sẽ hiển thị biến num đó là CHAR.

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

Đây không phải là vấn đề trong trường hợp này, bởi vì Oracle có thể xử lý phân tích chuỗi thành số nếu đó là số hợp lệ.

Khi chuỗi không thể phân tích thành số, thì Oracle không thể xử lý nó.

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

Với một trích dẫn, vì vậy đừng buộc Oracle phân tích thành số, sẽ ổn thôi:

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

Vì vậy, để trả lời câu hỏi ban đầu, cần thực hiện như mẫu này:

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

Có một cách khác để lưu trữ biến trong SQL * Plus bằng cách sử dụng Giá trị cột truy vấn .

Các COL [UMN] có new_value tùy chọn để giá trị lưu trữ từ truy vấn bằng tên trường.

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;

Như bạn có thể thấy, giá trị X.log đã được đặt thành biến ngu_var , vì vậy chúng ta có thể tìm thấy tệp X.log trong thư mục hiện tại có một số đăng nhập.


2

Đây là câu trả lời của bạn:

DEFINE num := 1;       -- The semi-colon is needed for default values.
SELECT &num FROM dual;

1
Giống tôi. Tôi sử dụng ODT và chạy: DEFINE num: = 1; CHỌN num TỪ kép; Và những gì tôi nhận được là: ORA-00904: "NUM": số nhận dạng không hợp lệ 00904. 00000 - "% s: số nhận dạng không hợp lệ" * Nguyên nhân: * Hành động: Lỗi tại Dòng: 2 Cột: 8
toha

0

Trong cóc tôi sử dụng công việc này:

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;

Sau đó, giá trị sẽ được in ra DBMS OutputWindow.

Tham khảo tại đâyđây2 .


0

Đôi khi bạn cần sử dụng biến macro mà không yêu cầu người dùng nhập giá trị. Thông thường điều này phải được thực hiện với các tham số tập lệnh tùy chọn. Các mã sau đây là đầy đủ chức năng

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

Mã tương tự bằng cách nào đó đã được tìm thấy trong thư mục rdbms / sql.


0

Một cách tiếp cận khả thi, nếu bạn chỉ cần xác định một tham số một lần và sao chép nó ở một vài nơi, là thực hiện một cái gì đó như thế này:

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

Mã này tạo ra một chuỗi gồm 8 chữ số ngẫu nhiên.

Lưu ý rằng tôi tạo một loại bí danh có tên str_sizelà hằng số 8. Nó được nối chéo để được sử dụng nhiều lần trong truy vấn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.