关于 DECLARE Block contains a commented dynamic input variable 的问题
Problems about DECLARE Block contains a commented dynamic input variable
我刚接触 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;
/
在这里你可以看到我评论声明代码radius NUMBER := &enter_value;
,然而,当我运行我的脚本在 SQL*Plus 或 SQL Developer,我总是收到像 please enter the value for enter_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 值调用该过程。
我建议为此使用 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
。
Update:为什么 SQLPlus 和 SQL Developer 检测 Substitution Variable
并为其请求一个值,即使它在 comment?
中也是如此
TLDR: SQL 客户端必须向服务器发送评论。注释中的预处理替换提供了更大的灵活性并使 SQL 客户端更简单。客户对控制替代行为有很好的支持。没有太多理由在最终代码中使用孤立替换变量。
加长版:
这些工具是数据库客户端——它们有很多功能,但首要的是它们的首要工作是收集输入 SQL,将其传送到数据库服务器并处理获取的数据。
Comment
s 需要与它们附带的 SQL
语句一起传送到数据库服务器。这是有原因的——所以用户可以在数据库中保存对他们编译的 SQL
代码的评论,当然,还有 compiler hint
s。
Substitution Variables
不会像评论那样随 SQL 一起传送到服务器。取而代之的是,它们会先 求值,然后将结果 SQLText
发送到服务器。 (您可以看到进入服务器的 SQL
已将其 Substitution Variables
替换为实际值。参见 V$SQLTEXT
)。
自服务器 "makes use" 评论以来,它使事情变得更加灵活并简化了 SQLPlus
甚至在评论中替换替换变量的事情。 (如果需要,这可以被覆盖。我将在下面展示)。 SQLPlus
,SQLDeveloper
, 等等 可以 被设计成忽略注释中的替换变量,但这会减少它们灵活,可能需要更多代码,因为他们需要识别注释并相应地逐行更改它们的行为。我将在下面进一步展示这种灵活性的一些示例。
以这种方式工作的工具没有太多缺点。
假设一个人只想在开发过程中忽略一段代码一分钟,然后快速 运行 一切。如果一个人拥有 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
允许您选择另一个字符作为替换标记。有很多选项可以控制事物。
如果一个人已经完成了最终 query
或 procedure
的开发,那么使用未定义替换的剩余 "orphan" 评论是无效的。开发完成后,孤儿替换应全部删除,剩余的任何内容都应引用有效的 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 计划:
------------------------------------------------------------------------------------
| 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
不同的目标进行全面扫描,并快速评估每个对查询的影响。
我刚接触 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;
/
在这里你可以看到我评论声明代码radius NUMBER := &enter_value;
,然而,当我运行我的脚本在 SQL*Plus 或 SQL Developer,我总是收到像 please enter the value for enter_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 值调用该过程。
我建议为此使用 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
。
Update:为什么 SQLPlus 和 SQL Developer 检测 Substitution Variable
并为其请求一个值,即使它在 comment?
TLDR: SQL 客户端必须向服务器发送评论。注释中的预处理替换提供了更大的灵活性并使 SQL 客户端更简单。客户对控制替代行为有很好的支持。没有太多理由在最终代码中使用孤立替换变量。
加长版: 这些工具是数据库客户端——它们有很多功能,但首要的是它们的首要工作是收集输入 SQL,将其传送到数据库服务器并处理获取的数据。
Comment
s 需要与它们附带的 SQL
语句一起传送到数据库服务器。这是有原因的——所以用户可以在数据库中保存对他们编译的 SQL
代码的评论,当然,还有 compiler hint
s。
Substitution Variables
不会像评论那样随 SQL 一起传送到服务器。取而代之的是,它们会先 求值,然后将结果 SQLText
发送到服务器。 (您可以看到进入服务器的 SQL
已将其 Substitution Variables
替换为实际值。参见 V$SQLTEXT
)。
自服务器 "makes use" 评论以来,它使事情变得更加灵活并简化了 SQLPlus
甚至在评论中替换替换变量的事情。 (如果需要,这可以被覆盖。我将在下面展示)。 SQLPlus
,SQLDeveloper
, 等等 可以 被设计成忽略注释中的替换变量,但这会减少它们灵活,可能需要更多代码,因为他们需要识别注释并相应地逐行更改它们的行为。我将在下面进一步展示这种灵活性的一些示例。
以这种方式工作的工具没有太多缺点。
假设一个人只想在开发过程中忽略一段代码一分钟,然后快速 运行 一切。如果一个人拥有 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
允许您选择另一个字符作为替换标记。有很多选项可以控制事物。
如果一个人已经完成了最终 query
或 procedure
的开发,那么使用未定义替换的剩余 "orphan" 评论是无效的。开发完成后,孤儿替换应全部删除,剩余的任何内容都应引用有效的 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 计划:
------------------------------------------------------------------------------------
| 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
不同的目标进行全面扫描,并快速评估每个对查询的影响。