有关DECLARE块的问题包含一个注释的动态输入变量

时间:2017-10-01 15:55:29

标签: 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 := &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;
/

然而,当我在 SQL * Plus 或<中运行我的脚本时,您可以看到我已经评论声明代码radius NUMBER := &enter_value; strong> SQL Developer ,我总是得到像please enter the value for enter_value这样的弹出消息。

相反,如果我在声明中删除此注释并将其置于其外部,那么将不再有提示。

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块是否无法接受评论?

感谢。

1 个答案:

答案 0 :(得分:4)

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

我建议使用FUNCTION代替PROCEDURE,但这是一个示例(也使用radius的参数)。 :

CREATE OR REPLACE PROCEDURE CAL_CIRCLE(P_RADIUS IN NUMBER, P_PI IN NUMBER) AS
  CIRCUMFERENCE DECIMAL(4, 2) := P_RADIUS * P_PI * 2;
  AREA          DECIMAL(4, 2) := P_PI * P_RADIUS ** 2;

  BEGIN

    DBMS_OUTPUT.put_line('For a circle with radius '
                         || P_RADIUS
                         || ',the circumference is '
                         || CIRCUMFERENCE
                         || ' and the area is '
                         || AREA
                         || '.' || 'Calculated with Pi=: ' || P_PI);
  END;
/

然后尝试一下:

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

如果你真的需要COMPILE具有替换值pi的常量(不推荐)的不同值的过程,你可以先用DEFINE设置替换变量。比如DEFINE pi_value = 3.1415;,然后再使用&pi_value

更新:为什么 SQLPlus SQL Developer 检测到Substitution Variable并为其请求值,即使它是在评论

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

<强>较长版本: 这些工具是数据库客户端 - 它们具有许多功能,但首要的是它们的第一项工作是收集输入SQL,将其传递到数据库服务器并处理提取的数据。

需要使用随附的Comment语句将

SQL传递到数据库服务器。这是有原因的 - 因此用户可以在数据库中保存对已编译的SQL代码的注释,当然也可以保存compiler hint的注释。

Substitution Variables不像SQL一样随服务器一起提供给服务器。相反,它们首先被评估,结果SQLText被发送到服务器。 (您可以看到进入服务器的SQL已将Substitution Variables替换为实际值。请参阅V$SQLTEXT

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

以这种方式工作的工具没有太大的缺点。

假设一个人只想在开发过程中忽略一小段代码并快速运行所有内容。如果一个人有DEFINE所有东西即使它没有被使用,或者删除所有已注释的代码以便它可以运行,那将是令人讨厌的。因此,这些工具允许您SET DEFINE OFF;并忽略变量。

例如,运行正常:

SET DEFINE OFF;
--SELECT '&MY_FIRST_IGNORED_VAR' FROM DUAL;
-- SELECT '&MY_SECOND_IGNORED_VAR' FROM DUAL;
SELECT 1919 FROM DUAL;

如果需要在查询中使用'&'本身,SQLPlus可让您选择其他字符作为替换标记。控制事物有很多选择。

如果一个人已经完成了最终queryprocedure的开发,​​那么使用undefined-substitution进行剩余的“孤儿”评论并不是一个有效的情况。开发完成后,应删除孤立替换,剩下的任何内容都应引用有效的DEFINE d变量。

这是一个在评论中使用处理substitution的示例。 假设你想调整一些表现不佳的SQL。您可以在HINT中使用替换变量(在注释中)以允许快速更改使用的索引或执行模式等,而无需实际更改查询脚本。

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;

通常,在此处根据TEST_VALUE进行预测的查询通常会在获取数据时使用其UNIQUE INDEX

SELECT TEST_VALUE FROM TEST_TABLE WHERE TEST_VALUE = 'VALUE-1919';

X-Plan:

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

如果此处有一堆表而不是一个表,则一个人可以DEFINE个不同的目标进行全面扫描,并快速评估对查询的每个影响。