จะประกาศตัวแปรและใช้งานในสคริปต์ Oracle SQL เดียวกันได้อย่างไร


133

ฉันต้องการเขียนโค้ดที่ใช้ซ้ำได้และจำเป็นต้องประกาศตัวแปรบางตัวในตอนต้นและนำมาใช้ซ้ำในสคริปต์เช่น:

DEFINE stupidvar = 'stupidvarcontent';

SELECT stupiddata
FROM stupidtable
WHERE stupidcolumn = &stupidvar;

ฉันจะประกาศตัวแปรและใช้ซ้ำในคำสั่งที่ตามมาได้อย่างไรเช่นในการใช้ SQLDeveloper


ความพยายามในการ

  • ใช้ส่วนประกาศและใส่คำสั่ง SELECT ต่อไปนี้ในและBEGIN END;เข้าถึงตัวแปรโดยใช้&stupidvar.
  • ใช้คีย์เวิร์ดDEFINEและเข้าถึงตัวแปร
  • ใช้คีย์เวิร์ดVARIABLEและเข้าถึงตัวแปร

แต่ฉันได้รับข้อผิดพลาดทุกประเภทในระหว่างการพยายามของฉัน (ตัวแปรที่ไม่ถูกผูก, ข้อผิดพลาดของไวยากรณ์, คาดว่าSELECT INTO... )


2
โปรดทราบว่าแนวทางในคำตอบที่ยอมรับโดย @APC สามารถใช้ได้โดยไม่ต้องใช้ PL / SQL เช่นในแผ่นงาน SQL Developer ตามคำถามของคุณ เพียงแค่ประกาศตัวแปรในหนึ่งบรรทัด (ไม่มีอัฒภาค) จากนั้นบรรทัด exec เพื่อกำหนดค่า (ลงท้ายด้วยอัฒภาค) จากนั้นจึงเลือกคำสั่งของคุณ สุดท้ายเรียกใช้เป็นสคริปต์ (F5) ไม่ใช่เป็นคำสั่ง (F9)
Amos M. Carpenter

คำตอบ:


139

มีหลายวิธีในการประกาศตัวแปรในสคริปต์ SQL * Plus

ประการแรกคือการใช้ VAR เพื่อประกาศตัวแปรการผูก กลไกในการกำหนดค่าให้กับ VAR คือการเรียกใช้ 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 มีประโยชน์อย่างยิ่งเมื่อเราต้องการเรียกใช้กระบวนงานที่เก็บไว้ซึ่งมีพารามิเตอร์ OUT หรือฟังก์ชัน

หรือเราสามารถใช้ตัวแปรทดแทน สิ่งเหล่านี้เหมาะสำหรับโหมดโต้ตอบ:

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>

เมื่อเรากำลังเขียนสคริปต์ที่เรียกใช้สคริปต์อื่นมันจะมีประโยชน์ในการกำหนดตัวแปรล่วงหน้า ข้อมูลโค้ดนี้ทำงานโดยไม่แจ้งให้ฉันป้อนค่า:

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>

ในที่สุดก็มีบล็อก PL / SQL ที่ไม่ระบุชื่อ อย่างที่คุณเห็นเรายังคงสามารถกำหนดค่าให้กับตัวแปรที่ประกาศแบบโต้ตอบได้:

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
ดีทั้งหมดยกเว้นการใช้คำว่า "bind variable" การประกาศ VAR สร้างตัวแปรการผูกในขณะที่ ACCEPT หรือ DEFINE สร้างตัวแปรการทดแทน
Dave Costa

1
เป็นไปได้ไหมที่จะต่อตัวแปร + สตริง
Ecropolis

@Ecropolis - ใช่ในช่วงการใช้งาน SQL Plus ตามค่าเริ่มต้น ใช้ SET CONCAT เพื่อกำหนดอักขระที่แยกชื่อของตัวแปรการแทนที่ออกจากอักขระที่เป็นตัวอักษรและตัวเลขที่ตามหลังชื่อตัวแปรทันที ใน PL / SQL หรือ SQL ใช้ท่อคู่ || เพื่อเชื่อมต่อ
Laszlo Lugosi

ถ้า SQL เป็นภาษามาตรฐานเหตุใดจึงยากที่จะค้นหาการอ้างอิงตามรูปแบบบัญญัติที่ใช้งานได้ทุกที่? WTF ???
jww

1
@jww - SQL เป็นมาตรฐาน แต่ไม่ได้ระบุไวยากรณ์ที่แน่นอนเสมอไปดังนั้นผลิตภัณฑ์ RDBMS ที่แตกต่างกันจึงสามารถใช้สิ่งต่าง ๆ ได้ วันที่เลขคณิตเป็นตัวอย่างที่ดี นอกจากนี้ผลิตภัณฑ์ฐานข้อมูลรุ่นเก่าเช่น Oracle มักจะแนะนำคุณสมบัติก่อนที่มาตรฐานจะครอบคลุมเช่นไวยากรณ์ CONNECT BY ตามลำดับชั้น แต่ในกรณีนี้เรากำลังพูดถึง SQL * Plus ซึ่งเป็นเครื่องมือไคลเอนต์และไม่ครอบคลุมโดยมาตรฐาน ANSI อยู่ดี
APC

28

ลองใช้เครื่องหมายคำพูดคู่ถ้าเป็นตัวแปรถ่าน:

DEFINE stupidvar = "'stupidvarcontent'";

หรือ

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

ขอบคุณสำหรับคำตอบของคุณ แต่ถ้าฉันรวม var ORA-01008: not all variables boundในราคาคู่ที่ผมได้รับ
bl4ckb0l7

1
แน่นอน! DEFINE num = 1; SELECT &num FROM dual;นำไปสู่: ORA-01008: not all variables bound
bl4ckb0l7

@ bl4ckb0l7 - ฉันพนันได้เลยว่าคุณกำลังลองสิ่งนี้ไม่ใช่ใน SQL * Plus
Laszlo Lugosi

20

ใน PL / SQL v.10

คำหลักประกาศใช้ในการประกาศตัวแปร

DECLARE stupidvar varchar(20);

เพื่อกำหนดค่าคุณสามารถตั้งค่าได้เมื่อคุณประกาศ

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

หรือเพื่อเลือกบางสิ่งลงในตัวแปรนั้นคุณใช้INTOคำสั่งอย่างไรก็ตามคุณต้องรวมคำสั่งเข้าด้วยกันBEGINและENDคุณต้องตรวจสอบให้แน่ใจว่ามีการส่งคืนค่าเดียวเท่านั้นและอย่าลืมอัฒภาค

ดังนั้นข้อความทั้งหมดจะออกมาดังนี้:

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

ตัวแปรของคุณสามารถใช้งานได้เฉพาะภายในBEGINและENDดังนั้นหากคุณต้องการที่จะใช้มากกว่าหนึ่งที่คุณจะต้องทำหลายBEGIN ENDห่อ

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;

หวังว่านี่จะช่วยคุณประหยัดเวลาได้บ้าง


7

หากคุณต้องการประกาศวันที่แล้วใช้ใน SQL Developer

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

SELECT * 
FROM proposal 
WHERE prop_start_dt = &PROPp_START_DT

5

แค่ต้องการเพิ่มคำตอบของMatas อาจจะเห็นได้ชัด แต่ฉันค้นหามานานแล้วว่าตัวแปรนั้นสามารถเข้าถึงได้เฉพาะในโครงสร้าง BEGIN-ENDดังนั้นหากคุณต้องการใช้ในบางรหัสในภายหลังคุณต้องใส่รหัสนี้ใน BEGIN บล็อก

โปรดทราบว่าบล็อกเหล่านี้สามารถซ้อนกันได้ :

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

คำถามเกี่ยวกับการใช้ตัวแปรในสคริปต์หมายความว่าสำหรับฉันมันจะถูกใช้ใน SQL * Plus

ปัญหาคือคุณพลาดคำพูดและ Oracle ไม่สามารถแยกวิเคราะห์ค่าเป็นตัวเลขได้

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

ตัวอย่างนี้ใช้งานได้ดีเนื่องจากการแปลงประเภทอัตโนมัติ (หรืออะไรก็ตามที่เรียกว่า)

หากคุณตรวจสอบโดยพิมพ์ DEFINE ใน SQL * Plus จะแสดงว่าตัวแปร num คือ CHAR

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

ไม่ใช่ปัญหาในกรณีนี้เนื่องจาก Oracle สามารถจัดการกับการแยกสตริงเป็นตัวเลขหากเป็นตัวเลขที่ถูกต้อง

เมื่อสตริงไม่สามารถแยกวิเคราะห์เป็นตัวเลขมากกว่าที่ Oracle ไม่สามารถจัดการกับมันได้

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

ด้วยใบเสนอราคาดังนั้นอย่าบังคับให้ Oracle แยกวิเคราะห์เป็นตัวเลขจะไม่เป็นไร:

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

ดังนั้นในการตอบคำถามเดิมควรทำเช่นนี้:

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

มีวิธีอื่น ๆ ในการจัดเก็บตัวแปรใน SQL * Plus โดยใช้เป็นค่าของแบบสอบถามคอลัมน์

COL [UMN] มีnew_valueตัวเลือกที่จะเก็บค่าจากแบบสอบถามโดยใช้ชื่อสนาม

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;

อย่างที่คุณเห็นค่า X.log ถูกตั้งค่าเป็นตัวแปรstupid_varดังนั้นเราจึงสามารถค้นหาไฟล์ X.log ในไดเร็กทอรีปัจจุบันซึ่งมีบางส่วนเข้าสู่ระบบ


2

นี่คือคำตอบของคุณ:

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

1
เหมือนกับฉัน. ฉันใช้ ODT และเรียกใช้: DEFINE num: = 1; เลือกจำนวนจากคู่; สิ่งที่ได้รับคือ: ORA-00904: "NUM": invalid identifier 00904. 00000 - "% s: invalid identifier" * สาเหตุ: * Action: Error at Line: 2 Column: 8
toha


0

บางครั้งคุณจำเป็นต้องใช้ตัวแปรมาโครโดยไม่ขอให้ผู้ใช้ป้อนค่า ส่วนใหญ่มักจะต้องทำด้วยพารามิเตอร์สคริปต์ที่เป็นทางเลือก รหัสต่อไปนี้สามารถใช้งานได้อย่างสมบูรณ์

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

พบรหัสที่คล้ายกันในไดเร็กทอรี rdbms / sql


0

แนวทางหนึ่งที่เป็นไปได้หากคุณต้องการระบุพารามิเตอร์เพียงครั้งเดียวและทำซ้ำในหลาย ๆ ที่ก็คือการทำสิ่งนี้:

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

รหัสนี้สร้างสตริงสุ่ม 8 หลัก

แจ้งให้ทราบว่าผมสร้างชนิดของนามแฝงที่มีชื่อที่มีอย่างต่อเนื่องstr_size 8มีการใช้ cross-join ที่จะใช้มากกว่าหนึ่งครั้งในแบบสอบถาม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.