如何在 oracle 中的包体中编写程序 - 错误?
how to write a procedure inside package body in oracle - error?
我有这个包,我在其中添加了一些值到 table,这有效....
create or replace PACKAGE BODY DC_LOAN_PKG
IS
PROCEDURE loan_book
(
loan_id IN DC_LOAN_EVIDENCE.ID%type,
b_id IN DC_LOAN_EVIDENCE.BOOK_ID%type,
m_id IN DC_LOAN_EVIDENCE.MEMBER_ID%type,
d_ofl IN DC_LOAN_EVIDENCE.DATE_OF_LOAN%type)
IS
BEGIN
INSERT
INTO DC_LOAN_EVIDENCE
(
ID,
BOOK_ID,
MEMBER_ID,
DATE_OF_LOAN
)
VALUES
(
DC_SEQ.NEXTVAL,
b_id,
m_id,
SYSDATE
);
COMMIT;
END loan_book;
现在,我想编写程序 return_book 和 extend_loan,我想在其中获取还书时的日期和延期后的新借阅日期。我做错了什么?这是示例....
PROCEDURE return_book
(
b_id IN DC_LOAN_EVIDENCE.BOOK_ID%type,
m_id IN DC_LOAN_EVIDENCE.MEMBER_ID%type,
r_dat IN DC_LOAN_EVIDENCE.RETURN_DATE%type
)
IS
dStartDate DATE := TO_DATE('2014-12-23', 'YYYY-MM-DD');
dEndDate DATE := TO_DATE('2015-01-23', 'YYYY-MM-DD');
BEGIN
UPDATE DC_LOAN_EVIDENCE
SET RETURN_DATE =r_dat
WHERE MEMBER_ID =m_id
AND BOOK_ID =b_id
AND RETURN_DATE BETWEEN dStartDate AND dEndDate ;
COMMIT;
END return_book;
PROCEDURE extend_loan
(
b_id IN DC_LOAN_EVIDENCE.BOOK_ID%type,
m_id IN DC_LOAN_EVIDENCE.MEMBER_ID%type,
d_ofl IN DC_LOAN_EVIDENCE.DATE_OF_LOAN%type
)
IS
BEGIN
UPDATE DC_LOAN_EVIDENCE
SET DATE_OF_LOAN =d_ofl
WHERE MEMBER_ID =m_id
AND BOOK_ID =b_id;
COMMIT;
END extend_loan;
END DC_LOAN_PKG;
您需要将内部过程保留在主过程的声明块中。
类似于-
PROCEDURE return_book(
b_id IN DC_LOAN_EVIDENCE.BOOK_ID%type,
m_id IN DC_LOAN_EVIDENCE.MEMBER_ID%type,
r_dat IN DC_LOAN_EVIDENCE.RETURN_DATE%type )
IS
dStartDate DATE := TO_DATE('2014-12-23', 'YYYY-MM-DD');
dEndDate DATE := TO_DATE('2015-01-23', 'YYYY-MM-DD');
PROCEDURE extend_loan(
b_id IN DC_LOAN_EVIDENCE.BOOK_ID%type,
m_id IN DC_LOAN_EVIDENCE.MEMBER_ID%type,
d_ofl IN DC_LOAN_EVIDENCE.DATE_OF_LOAN%type )
IS
BEGIN
UPDATE DC_LOAN_EVIDENCE
SET DATE_OF_LOAN =d_ofl
WHERE MEMBER_ID =m_id
AND BOOK_ID =b_id;
COMMIT;
END extend_loan;
BEGIN
UPDATE DC_LOAN_EVIDENCE
SET RETURN_DATE =r_dat
WHERE MEMBER_ID =m_id
AND BOOK_ID =b_id
AND RETURN_DATE BETWEEN dStartDate AND dEndDate ;
COMMIT;
END return_book;
END DC_LOAN_PKG;
我坚持要你把它包起来。通过这样的独立程序,您将引入依赖链。这可以避免使用包。你可以实现封装,它有很多优点,就像 Tom Kyte 说的那样 -
打破依赖链(当你安装一个新的包主体时没有级联失效——如果
你有调用过程的过程——编译一个会使你的数据库无效)
支持封装——我将被允许编写模块化的、易于理解的代码——而不是
然后 MONOLITHIC,不可理解的程序
显着增加我的命名空间。包名称在模式中必须是唯一的,但我可以
许多程序跨同名程序包而不会发生冲突
支持重载
在需要时支持会话变量
促进整体良好的编码技术,让您编写模块化代码的东西,
可以理解,合乎逻辑地组合在一起....
编辑如果你有独立的程序,那么你需要单独拥有它们。
CREATE OR replace PACKAGE BODY dc_loan_pkg
IS
-- Procedure 1
PROCEDURE Loan_book(loan_id IN dc_loan_evidence.id%TYPE,
b_id IN dc_loan_evidence.book_id%TYPE,
m_id IN dc_loan_evidence.member_id%TYPE,
d_ofl IN dc_loan_evidence.date_of_loan%TYPE)
IS
BEGIN
INSERT INTO dc_loan_evidence
(id,
book_id,
member_id,
date_of_loan)
VALUES ( dc_seq.NEXTVAL,
b_id,
m_id,
SYSDATE );
COMMIT;
END loan_book;
-- Procedure 2
PROCEDURE Return_book (b_id IN dc_loan_evidence.book_id%TYPE,
m_id IN dc_loan_evidence.member_id%TYPE,
r_dat IN dc_loan_evidence.return_date%TYPE)
IS
dstartdate DATE := To_date('2014-12-23', 'YYYY-MM-DD');
denddate DATE := To_date('2015-01-23', 'YYYY-MM-DD');
BEGIN
UPDATE dc_loan_evidence
SET return_date = r_dat
WHERE member_id = m_id
AND book_id = b_id
AND return_date BETWEEN dstartdate AND denddate;
COMMIT;
END return_book;
-- Procedure 3
PROCEDURE Extend_loan(b_id IN dc_loan_evidence.book_id%TYPE,
m_id IN dc_loan_evidence.member_id%TYPE,
d_ofl IN dc_loan_evidence.date_of_loan%TYPE)
IS
BEGIN
UPDATE dc_loan_evidence
SET date_of_loan = d_ofl
WHERE member_id = m_id
AND book_id = b_id;
COMMIT;
END extend_loan;
END dc_loan_pkg;
/
您的原始过程 loan_book
有两个您不使用的参数 - 无论您作为 id
和 book_loan_date
传递的什么都会被忽略,并被序列值和当前日期分别。对 ID 使用序列是有意义的,但让用户传递自己的值会造成混淆,因此您或许应该删除该参数。您是使用 sysdate
还是贷款日期的传递值取决于您的业务规则,但目前充其量也令人困惑。一个妥协可能是将该参数默认为 sysdate
,因此可以在需要时覆盖它。
您的 return_book
过程不会匹配 loan_book
创建的任何记录,因为它正在检查 return_date
,它将为空(除非您已经在与此同时);如果您只能 return 一次贷款,那张支票似乎很奇怪。本质上,AND RETURN_DATE BETWEEN dStartDate AND dEndDate
不会匹配任何 return_date
为空的行。
你的 extend_loan
过程似乎确实有效,假设你正在传递正确的书籍和成员值。
如果您没有看到 date_of_loan
被扩展,那么您一定是向过程传递了错误的值。
但是,将图书和会员传递给您的新程序意味着一本书只能借给会员一次。如果您想允许同一本书被多次借阅,您应该传递 ID 值,因为它(大概!)是唯一的。也许您在 return_book
中的 return_date
过滤器实际上应该检查 date_of_loan
是最近的,以试图解决这种歧义。相反,传递 ID 会更好;明确寻找非 return 版书籍,and/or 特定 book/member 的最近贷款,在某种程度上也可以工作,但不太稳健。
在过程内部提交通常也被认为是不好的做法,最好让调用者决定是提交还是回滚。
我有这个包,我在其中添加了一些值到 table,这有效....
create or replace PACKAGE BODY DC_LOAN_PKG
IS
PROCEDURE loan_book
(
loan_id IN DC_LOAN_EVIDENCE.ID%type,
b_id IN DC_LOAN_EVIDENCE.BOOK_ID%type,
m_id IN DC_LOAN_EVIDENCE.MEMBER_ID%type,
d_ofl IN DC_LOAN_EVIDENCE.DATE_OF_LOAN%type)
IS
BEGIN
INSERT
INTO DC_LOAN_EVIDENCE
(
ID,
BOOK_ID,
MEMBER_ID,
DATE_OF_LOAN
)
VALUES
(
DC_SEQ.NEXTVAL,
b_id,
m_id,
SYSDATE
);
COMMIT;
END loan_book;
现在,我想编写程序 return_book 和 extend_loan,我想在其中获取还书时的日期和延期后的新借阅日期。我做错了什么?这是示例....
PROCEDURE return_book
(
b_id IN DC_LOAN_EVIDENCE.BOOK_ID%type,
m_id IN DC_LOAN_EVIDENCE.MEMBER_ID%type,
r_dat IN DC_LOAN_EVIDENCE.RETURN_DATE%type
)
IS
dStartDate DATE := TO_DATE('2014-12-23', 'YYYY-MM-DD');
dEndDate DATE := TO_DATE('2015-01-23', 'YYYY-MM-DD');
BEGIN
UPDATE DC_LOAN_EVIDENCE
SET RETURN_DATE =r_dat
WHERE MEMBER_ID =m_id
AND BOOK_ID =b_id
AND RETURN_DATE BETWEEN dStartDate AND dEndDate ;
COMMIT;
END return_book;
PROCEDURE extend_loan
(
b_id IN DC_LOAN_EVIDENCE.BOOK_ID%type,
m_id IN DC_LOAN_EVIDENCE.MEMBER_ID%type,
d_ofl IN DC_LOAN_EVIDENCE.DATE_OF_LOAN%type
)
IS
BEGIN
UPDATE DC_LOAN_EVIDENCE
SET DATE_OF_LOAN =d_ofl
WHERE MEMBER_ID =m_id
AND BOOK_ID =b_id;
COMMIT;
END extend_loan;
END DC_LOAN_PKG;
您需要将内部过程保留在主过程的声明块中。
类似于-
PROCEDURE return_book(
b_id IN DC_LOAN_EVIDENCE.BOOK_ID%type,
m_id IN DC_LOAN_EVIDENCE.MEMBER_ID%type,
r_dat IN DC_LOAN_EVIDENCE.RETURN_DATE%type )
IS
dStartDate DATE := TO_DATE('2014-12-23', 'YYYY-MM-DD');
dEndDate DATE := TO_DATE('2015-01-23', 'YYYY-MM-DD');
PROCEDURE extend_loan(
b_id IN DC_LOAN_EVIDENCE.BOOK_ID%type,
m_id IN DC_LOAN_EVIDENCE.MEMBER_ID%type,
d_ofl IN DC_LOAN_EVIDENCE.DATE_OF_LOAN%type )
IS
BEGIN
UPDATE DC_LOAN_EVIDENCE
SET DATE_OF_LOAN =d_ofl
WHERE MEMBER_ID =m_id
AND BOOK_ID =b_id;
COMMIT;
END extend_loan;
BEGIN
UPDATE DC_LOAN_EVIDENCE
SET RETURN_DATE =r_dat
WHERE MEMBER_ID =m_id
AND BOOK_ID =b_id
AND RETURN_DATE BETWEEN dStartDate AND dEndDate ;
COMMIT;
END return_book;
END DC_LOAN_PKG;
我坚持要你把它包起来。通过这样的独立程序,您将引入依赖链。这可以避免使用包。你可以实现封装,它有很多优点,就像 Tom Kyte 说的那样 -
打破依赖链(当你安装一个新的包主体时没有级联失效——如果 你有调用过程的过程——编译一个会使你的数据库无效)
支持封装——我将被允许编写模块化的、易于理解的代码——而不是 然后 MONOLITHIC,不可理解的程序
显着增加我的命名空间。包名称在模式中必须是唯一的,但我可以 许多程序跨同名程序包而不会发生冲突
支持重载
在需要时支持会话变量
促进整体良好的编码技术,让您编写模块化代码的东西, 可以理解,合乎逻辑地组合在一起....
编辑如果你有独立的程序,那么你需要单独拥有它们。
CREATE OR replace PACKAGE BODY dc_loan_pkg
IS
-- Procedure 1
PROCEDURE Loan_book(loan_id IN dc_loan_evidence.id%TYPE,
b_id IN dc_loan_evidence.book_id%TYPE,
m_id IN dc_loan_evidence.member_id%TYPE,
d_ofl IN dc_loan_evidence.date_of_loan%TYPE)
IS
BEGIN
INSERT INTO dc_loan_evidence
(id,
book_id,
member_id,
date_of_loan)
VALUES ( dc_seq.NEXTVAL,
b_id,
m_id,
SYSDATE );
COMMIT;
END loan_book;
-- Procedure 2
PROCEDURE Return_book (b_id IN dc_loan_evidence.book_id%TYPE,
m_id IN dc_loan_evidence.member_id%TYPE,
r_dat IN dc_loan_evidence.return_date%TYPE)
IS
dstartdate DATE := To_date('2014-12-23', 'YYYY-MM-DD');
denddate DATE := To_date('2015-01-23', 'YYYY-MM-DD');
BEGIN
UPDATE dc_loan_evidence
SET return_date = r_dat
WHERE member_id = m_id
AND book_id = b_id
AND return_date BETWEEN dstartdate AND denddate;
COMMIT;
END return_book;
-- Procedure 3
PROCEDURE Extend_loan(b_id IN dc_loan_evidence.book_id%TYPE,
m_id IN dc_loan_evidence.member_id%TYPE,
d_ofl IN dc_loan_evidence.date_of_loan%TYPE)
IS
BEGIN
UPDATE dc_loan_evidence
SET date_of_loan = d_ofl
WHERE member_id = m_id
AND book_id = b_id;
COMMIT;
END extend_loan;
END dc_loan_pkg;
/
您的原始过程 loan_book
有两个您不使用的参数 - 无论您作为 id
和 book_loan_date
传递的什么都会被忽略,并被序列值和当前日期分别。对 ID 使用序列是有意义的,但让用户传递自己的值会造成混淆,因此您或许应该删除该参数。您是使用 sysdate
还是贷款日期的传递值取决于您的业务规则,但目前充其量也令人困惑。一个妥协可能是将该参数默认为 sysdate
,因此可以在需要时覆盖它。
您的 return_book
过程不会匹配 loan_book
创建的任何记录,因为它正在检查 return_date
,它将为空(除非您已经在与此同时);如果您只能 return 一次贷款,那张支票似乎很奇怪。本质上,AND RETURN_DATE BETWEEN dStartDate AND dEndDate
不会匹配任何 return_date
为空的行。
你的 extend_loan
过程似乎确实有效,假设你正在传递正确的书籍和成员值。
如果您没有看到 date_of_loan
被扩展,那么您一定是向过程传递了错误的值。
但是,将图书和会员传递给您的新程序意味着一本书只能借给会员一次。如果您想允许同一本书被多次借阅,您应该传递 ID 值,因为它(大概!)是唯一的。也许您在 return_book
中的 return_date
过滤器实际上应该检查 date_of_loan
是最近的,以试图解决这种歧义。相反,传递 ID 会更好;明确寻找非 return 版书籍,and/or 特定 book/member 的最近贷款,在某种程度上也可以工作,但不太稳健。
在过程内部提交通常也被认为是不好的做法,最好让调用者决定是提交还是回滚。