如何在oracle中编写一个包体内的程序 - 错误?

时间:2015-01-12 08:41:44

标签: oracle

我有这个包,我在表中添加了一些值,这可行.... [/ p>

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,我希望在返回书籍时获得DATE,并在扩展后获得新的贷款日期。我做错了什么?这是一个例子......

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;

2 个答案:

答案 0 :(得分: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');
      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所说 -

  • 打破依赖关系链(安装新的包体时没有级联失效 - 如果 你有程序调用程序 - 编译一个程序会使你的数据库失效)

  • 支持封装 - 我将被允许编写MODULAR,易于理解的代码 - 而不是 然后是单一的,不可理解的程序

  • 可测量地增加我的命名空间。包名称必须在模式中是唯一的,但我可以 跨包的许多程序具有相同的名称而不会发生冲突

  • 支持重载

  • 在您需要时支持会话变量

  • 促进整体良好的编码技术,让你编写模块化的代码, 可理解的,逻辑上组合在一起....

编辑如果您的程序是独立的,那么您需要单独购买。

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

答案 1 :(得分:0)

您的原始程序loan_book有两个您不会使用的参数 - 无论您传递的是id还是book_loan_date都会被忽略,并被序列值替换为现在的日期。使用ID的序列是有道理的,但让用户传递他们自己的值会让人感到困惑,所以你应该删除那个参数。您是使用sysdate还是贷款日期的传递值取决于您的业务规则,但目前这也是令人困惑的时刻。折衷方案可能是将该参数默认为sysdate,因此可以在需要时覆盖它。

您的return_book程序不会与loan_book创建的任何记录相匹配,因为它会检查return_date,这将是空的(除非您已经在此期间手动设置);如果你只能退还一次贷款,那检查似乎很奇怪。实质上,AND RETURN_DATE BETWEEN dStartDate AND dEndDate将不匹配return_date为空的任何行。

假设您传递了正确的图书和会员价值,您的extend_loan程序似乎确实有效。

SQL Fiddle

如果您没有看到date_of_loan被扩展,那么您必须将错误的值传递给该过程。

但是,将书籍和成员传递给新程序意味着一本书只能借给一个成员一次。如果你想允许多次借用同一本书,你应该传递ID值,因为它(大概是!)是唯一的。也许return_date中的return_book过滤器实际上应该检查date_of_loan是否是最近的,以试图解决这种歧义。传递ID会更好;明确地寻找未归还的书籍,和/或特定书籍/会员的最新贷款,在某种程度上也会起作用,但不那么健壮。

在程序中提交通常也被认为是不好的做法,让调用者决定是提交还是回滚更好。