如何通过SELECT语句声明和初始化一个包变量

5

请问有人可以帮我理解为什么我可以在一个包中声明一个硬编码日期值,但不能从查询中赋值?我看过很多例子(包括参考书),都展示了硬编码值的声明,但我无法找到通过查询将值赋给变量的例子。

这是可以的:

create or replace package body PACKAGE_NAME AS
    tDate DATE := '2012-05-30';
    -- ...procedures follow

这是允许的:

create or replace package body PACKAGE_NAME AS
    tDate DATE := sysdate;

这是不允许的:

create or replace package body PACKAGE_NAME AS
    tDate DATE := select MAX(date_) from Table_Name;

我已经尝试了多种方法,即使无法工作我也能在程序本身中使用它。但是我想知道为什么我不能用这种方式给tDate赋值?具体的错误是:

遇到符号“SELECT”,但要求的是....

补充一下,在存储过程中可以通过查询分配变量值,但是同样的过程似乎在包体中无法工作。

PROCEDURE Proc_Name IS
tDate Date;
BEGIN
SELECT MAX(date_) into tDate from Table_Name;
2个回答

11

您需要在包体中创建一个包初始化块。这是一个相对晦涩的PL/SQL包知识,但它存在并且可以使用。以下是一个示例:

CREATE OR REPLACE PACKAGE TEST_PKG IS
  tDate  DATE;
END TEST_PKG;

这里我们创建了一个包规范,其中仅包含一个DATE变量。现在我们将创建一个简单的主体,使用SELECT语句初始化该变量:

CREATE OR REPLACE PACKAGE BODY TEST_PKG IS
  -- package-private variables go first (if any)
(...) 
  -- then the public functions/procedures
(...)
  -- then a final BEGIN-END block which is the package initialization block
BEGIN
  SELECT SYSDATE
    INTO tDATE
    FROM DUAL;
EXCEPTION  -- you can have exception handlers in your initialization block
  WHEN OTHERS THEN
    NULL;  -- pointless here, but this is just an example
    RAISE;
END TEST_PKG;

现在如果您执行以下操作:

begin
  -- Test statements here
  DBMS_OUTPUT.PUT_LINE('TEST_PKG.tDate = ' || TEST_PKG.tDate);
end;

它应该打印出当前日期。

分享并享受。


感谢您回答我的问题。这肯定应该有效,尽管我还没有能够将其放入我的包中。当我尝试包含包体时,我遇到了“遇到符号'CREATE'”的错误。这可能只是我的环境出了问题。我仍然不明白为什么他们会让我分配一个硬编码值,但不能通过查询分配一个有效值。为什么我必须实现这种“神秘”的方法来设置变量值?再次感谢。 - dee
1
包规范和主体需要分别创建。因此,您应该先有 CREATE OR REPLACE PACKAGE MY_PACKAGE...END MY_PACKAGE; 然后是 CREATE OR REPLACE PACKAGE BODY MY_PACKAGE...END MY_PACKAGE;。至于“为什么必须这样做……”——长答案是,您不能在变量初始化中使用可执行语句(例如 SELECT),这正是包初始化块存在的原因——以便您可以在会话访问初始化会话变量的包时执行代码。简短的答案是“因为你必须这样做”。 :-) 分享并享受。 - Bob Jarvis - Слава Україні
感谢您解释原因,即使长答案和短答案似乎都是:“为什么?因为这是科学,所以才会这样!”Dr.F.我仍然对此有问题,但我会向周围的人询问,并重新阅读关于Oracle包构建的规范,我很可能会在周末弄清楚。 - dee
1
我不明白为什么你把变量声明从包体移到了规范中。这取决于你是否想让它对外部可见,可以放在任何一个地方。初始化也是如此。 - Shannon Severance
@ShannonSeverance - 这只是举例说明的目的 - 我想展示创建规范和主体的示例,因此在规范中创建了变量。当然,您是正确的,初始化块可以处理在任何地方声明的变量。 - Bob Jarvis - Слава Україні

0

当直接选择变量时,您需要使用INTO

select MAX(date_) 
INTO tDate
from Table_Name;

感谢您的快速回复。我可以让存储过程正常工作,但无法让包正常工作。 存储过程名称_是tDate日期; BEGIN SELECT INTO tDate等...但对于包体Package_Name,tDate日期; SELECT MAX(date_)INTO等... - dee
一个包体应该包含过程和函数定义,它本身不是一个PL/SQL块。tDate声明作为包的全局变量是有效的,但SELECT语句应该出现在一个过程或函数中。 - Datajam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接