Plsql 关于DECLARE块包含注释动态输入变量的问题

Plsql 关于DECLARE块包含注释动态输入变量的问题,plsql,oracle11g,oracle-sqldeveloper,sqlplus,Plsql,Oracle11g,Oracle Sqldeveloper,Sqlplus,我刚刚接触PL/SQL 我写了一个块来计算圆的半径和周长,如下所示: SET SERVEROUTPUT ON; CREATE OR REPLACE PROCEDURE cal_circle AS -- DECLARE pi CONSTANT NUMBER := 3.1415926; radius NUMBER := 3; -- to make it more dynamic I can set -- radius NUMBER

我刚刚接触PL/SQL

我写了一个块来计算圆的半径和周长,如下所示:

SET SERVEROUTPUT ON;

CREATE OR REPLACE PROCEDURE cal_circle AS
-- DECLARE

  pi              CONSTANT NUMBER := 3.1415926;
  radius          NUMBER := 3;

  -- to make it more dynamic I can set 
  -- radius NUMBER := &enter_value;

  circumference   DECIMAL(4,2) := radius * pi * 2;
  area            DECIMAL(4,2) := pi * radius ** 2;

BEGIN

  -- DBMS_OUTPUT.PUT_LINE('Enter a valur of radius: '|| radius);
  dbms_output.put_line('For a circle with radius '
   || radius
   || ',the circumference is '
   || circumference
   || ' and the area is '
   || area
   || '.');
END;
/
在这里,您可以看到我已经注释了声明代码
半径编号:=&enter_值SQL*PlusSQL Developer中运行脚本时,总会收到弹出消息,如
请输入enter\u value
的值

相反,如果我在declare中删除这个注释并将其放在它的外部,那么将不再有提示

SET SERVEROUTPUT ON;

/* to make it more dynamic, I can set 
   radius NUMBER := &enter_value;
*/

CREATE OR REPLACE PROCEDURE cal_circle AS
-- DECLARE

  pi              CONSTANT NUMBER := 3.1415926;
  radius          NUMBER := 3;
  circumference   DECIMAL(4,2) := radius * pi * 2;
  area            DECIMAL(4,2) := pi * radius ** 2;

BEGIN
......
这里我想澄清的是,当我试图注释一个动态变量时,这是否意味着DECLARE块不能接受注释


谢谢。

您可以使用参数而不是替换变量来允许不同的用户使用不同的pi值调用过程

为此,我建议使用
函数
而不是
过程
,但这里有一个示例(也使用
半径
的参数):

然后尝试一下:

BEGIN
  CAL_CIRCLE(3, 3.14);
END;
/

For a circle with radius 3,the circumference is 18.84 and the area is
28.26.Calculated with Pi=: 3.14


BEGIN
  CAL_CIRCLE(3, 3.14159);
END;
/

For a circle with radius 3,the circumference is 18.85 and the area is
28.27.Calculated with Pi=: 3.14159
如果您确实需要
编译
过程,并使用替换值pi为其常数(不推荐)设置不同的值,则可以首先使用
定义
设置替换变量。如
定义pi_值=3.1415,然后稍后使用
和pi_值

Update:为什么SQLPlussqldeveloper会检测到
替换变量
,并为其请求一个值,即使它在注释中也是如此

TLDR:SQL客户端必须向服务器发送注释。预处理注释中的替换提供了更大的灵活性,并使SQL客户机更简单。客户对控制替代行为有很好的支持。在最终确定的代码中没有太多理由使用孤立替代变量

较长版本: 这些工具都是数据库客户机——它们有很多特性,但最重要的是,它们的第一项工作是收集输入SQL,将其传递到数据库服务器,并处理获取的数据

Comment
s需要连同其附带的
SQL
语句一起发送到数据库服务器。这是有原因的——因此用户可以在数据库中保存他们编译的
SQL
代码的注释,当然也可以保存
编译器提示的注释

替换变量
不会像注释一样随SQL一起传递到服务器。而是首先对它们求值,并将结果
SQLText
发送到服务器。(您可以看到进入服务器的
SQL
将其
替换变量
替换为实际值。请参见
V$SQLTEXT

由于服务器“利用”了注释,因此它使事情更加灵活,并简化了
SQLPlus
的工作,以替换注释中的替换变量。(如果需要,这可以被覆盖。我将在下面展示)
SQLPlus
SQLDeveloper
可能被设计为忽略注释中的替换变量,但这会降低它们的灵活性,可能需要更多的代码,因为它们需要识别注释并相应地逐行更改其行为。下面我将进一步展示这种灵活性的一些示例

以这种方式工作的工具没有什么缺点。

假设一个人只想在开发过程中忽略一段代码,然后快速运行所有代码。如果一个人有
DEFINE
所有东西,即使它没有被使用,或者删除所有注释过的代码,只是为了让它可以运行,这将是一件很烦人的事情。因此,这些工具允许您
设置DEFINE OFF并忽略变量

例如,这运行良好:

SET DEFINE OFF;
--SELECT '&MY_FIRST_IGNORED_VAR' FROM DUAL;
-- SELECT '&MY_SECOND_IGNORED_VAR' FROM DUAL;
SELECT 1919 FROM DUAL;
如果需要在查询中使用
&
本身,
SQLPlus
允许您选择另一个字符作为替换标记。控制事情有很多选择

如果一个人已经完成了自己的最终
查询
过程
,那么使用未定义替换的剩余“孤立”注释是无效的。开发完成后,应删除所有孤立替换,剩余的任何内容都应引用有效的
DEFINE
d变量

下面是一个在注释中使用处理
substitution
s的示例。 假设您想调优一些性能较差的
SQL
。您可以在
HINT
s(注释中)中使用替换变量,以允许快速更改使用的索引或执行模式等,而无需实际更改查询脚本

CREATE TABLE TEST_TABLE_1(TEST_KEY NUMBER PRIMARY KEY,
TEST_VALUE VARCHAR2(128) NOT NULL,
CONSTRAINT TEST_VALUE_UNQ UNIQUE (TEST_VALUE));

INSERT INTO TEST_TABLE
  SELECT LEVEL, 'VALUE-'||LEVEL
  FROM DUAL CONNECT BY LEVEL <= 5000;
X平面图:

------------------------------------------------------------------------------------  
| Id  | Operation         | Name           | Rows  | Bytes | Cost (%CPU)| Time     |  
------------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT  |                |     1 |    66 |     1   (0)| 00:00:01 |  
|*  1 |  INDEX UNIQUE SCAN| TEST_VALUE_UNQ |     1 |    66 |     1   (0)| 00:00:01 |  
------------------------------------------------------------------------------------ 
但可以通过提示强制进行完全扫描。通过在提示(注释)中使用替换变量,可以允许替换变量的值指导查询执行:

DEFINE V_WHICH_FULL_SCAN = 'TEST_TABLE';
SELECT /*+ FULL(&V_WHICH_FULL_SCAN) */ TEST_VALUE FROM TEST_TABLE WHERE TEST_VALUE = 'VALUE-1919';
此处,替换变量(在其注释中)已更改查询执行

X平面图:

--------------------------------------------------------------------------------  
| Id  | Operation         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |  
--------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT  |            |    23 |  1518 |     9   (0)| 00:00:01 |  
|*  1 |  TABLE ACCESS FULL| TEST_TABLE |    23 |  1518 |     9   (0)| 00:00:01 |  
-------------------------------------------------------------------------------- 

如果这里有一堆表,而不是一个表,那么一个人可以定义不同的目标进行全面扫描,并快速评估每个对查询的影响。

您可以使用参数而不是替换变量,以允许不同的用户使用不同的pi值调用过程

为此,我建议使用
函数
而不是
过程
,但这里有一个示例(也使用
半径
的参数):

然后尝试一下:

BEGIN
  CAL_CIRCLE(3, 3.14);
END;
/

For a circle with radius 3,the circumference is 18.84 and the area is
28.26.Calculated with Pi=: 3.14


BEGIN
  CAL_CIRCLE(3, 3.14159);
END;
/

For a circle with radius 3,the circumference is 18.85 and the area is
28.27.Calculated with Pi=: 3.14159
如果您确实需要
编译
过程,并使用替换值pi为其常数(不推荐)设置不同的值,则可以首先使用
定义
设置替换变量。如
定义pi_值=3.1415,然后使用
和pi_值
--------------------------------------------------------------------------------  
| Id  | Operation         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |  
--------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT  |            |    23 |  1518 |     9   (0)| 00:00:01 |  
|*  1 |  TABLE ACCESS FULL| TEST_TABLE |    23 |  1518 |     9   (0)| 00:00:01 |  
--------------------------------------------------------------------------------