CURSOR或其他解决方案中的例外情况

时间:2014-03-20 22:21:47

标签: sql oracle

我有卖票的DB。我有这样的程序,我从一些种族中计算所有卖出的钱:

CREATE OR REPLACE PROCEDURE Total_money(depart IN RACE.DEPART_PLACE%TYPE, 
  dest IN RACE.DESTINATION_PLACE%TYPE, total OUT TICKET.PRICE%TYPE)
  IS
  CURSOR tickets
    IS SELECT t.CLIENT_ID, t.PRICE FROM TICKET t JOIN VAGON v ON t.VAGON_ID = v.VAGON_ID
        JOIN RACE r ON v.RACE_ID = r.RACE_ID
        WHERE r.DEPART_PLACE = depart AND r.DESTINATION_PLACE = dest;
  BEGIN 
  FOR t IN tickets
    LOOP
      IF t.CLIENT_ID IS NOT NULL THEN 
        total := total + t.PRICE;
      END IF;
    END LOOP;
  END;

第一个问题:我可以在CURSOR声明中添加例外吗?或者当我通过错误的出发名称或火车的目的地名称时,我该怎么办?或者这些名称在DB中不存在。然后它将创建一个空光标。并返还0钱。如何控制?

第二个问题:在程序声明之后,我运行这些命令:

 DECLARE t TICKET.PRICE%TYPE;
      t:=0;
    execute total_money('Kyiv', 'Warsaw', t)

但是有一个错误(PLS-00103遇到符号......) 第一个问题:如何解决?

1 个答案:

答案 0 :(得分:1)

一个简单的检查就是测试循环后total是否为非零:

...
  END LOOP;
  IF total <= 0 THEN
    RAISE_APPLICATION_ERROR(-20001, 'Toal zero, invalid arguments?');
  END IF;
END;

如果总数合法地为零(这似乎不太可能,除了客户端ID检查),你可以有一个标志的计数器并检查:

CREATE ... IS
  found BOOLEAN := false;
  CURSOR ...
BEGIN
  total := 0;
  FOR t IN tickets
    LOOP
      found := true;
      IF t.CLIENT_ID IS NOT NULL THEN 
        total := total + t.PRICE;
      END IF;
  END LOOP;
  IF NOT found THEN
    RAISE_APPLICATION_ERROR(-20001, 'No records, invalid arguments?');
  END IF;
END;

execute是一个SQL * Plus命令,因此我不确定您希望这种方式工作的方式。你可以使用这样的匿名块:

DECLARE
  t TICKET.PRICE%TYPE;
BEGIN
  total_money('Kyiv', 'Warsaw', t);
  -- do something with t
END;
/

或者使用SQL * Plus(或SQL Developer)变量,您可以这样做:

variable t number;
execute total_money('Kyiv', 'Warsaw', :t);
print t

我将它从程序改为功能;在其中声明一个总数,将其初始化为零,然后返回该参数而不是out参数。然后,您可以通过简单的选择从PL / SQL或SQL中调用它。

正如ElectricLlama指出的那样,你不需要光标;并且根本不需要在PL / SQL中执行此操作 - 只需使用聚合sum()。我认为这是一个学习游标的练习吗?