PL/SQL 游标 - 从多个表中检索数据

PL/SQL Cursors - Retrieving data from multiple tables

我需要输入产品代码作为参数来检索所述产品和其他信息。我需要比我提供的更多的信息,我已经开始小规模尝试尽早调试任何错误,但我不明白为什么下面的代码不起作用。我正在使用 SQLPlus,将不胜感激任何帮助。

CREATE OR REPLACE PROCEDURE product_info(PRODUCT_NO IN CHAR)
AS
    v_product PRODUCTS%ROWTYPE;
    v_suborders  SUBORDERS.ORDER_NO%TYPE;

    CURSOR cur_products IS
    SELECT p.name, p.prod_id, p.description, p.unit_price, s.order_no
    FROM PRODUCTS P, SUBORDERS S
    WHERE p.prod_id = product_no;

BEGIN
OPEN cur_products;
LOOP
FETCH cur_products INTO v_product, v_suborders;

  DBMS_OUTPUT.PUT_LINE('Product Code: ' || v_product.prod_id 
  || ' Name: ' || v_product.name 
  || ' Description: ' || v_product.description
  || ' Price: ' || v_product.unit_price
  || ' Order: ' || v_suborders);
END LOOP;
EXCEPTION
WHEN no_data_found THEN 
DBMS_OUTPUT.PUT_LINE ('Product number does not exist'); 
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE ('Operation failed  ' || 'SQLCODE: ' || SQLCODE); 
ROLLBACK;
END; 
/

当我们获取一个变量时,它的结构必须与我们正在获取的查询的投影相匹配。或者,如果我们要获取多个变量,我们需要在投影中每一列有一个变量。您的代码也没有。

最简单的解决方案是使用光标定义变量,如下所示:

    CURSOR cur_products IS
        SELECT p.name, p.prod_id, p.description, p.unit_price, s.order_no
        FROM PRODUCTS P, SUBORDERS S
        WHERE p.prod_id = product_no;
    v_rec  cur_products%ROWTYPE;

BEGIN
    OPEN cur_products;
    LOOP
    FETCH cur_products INTO v_rec;
    ...

另一种解决方案是使用隐式游标。您可以这样重写代码:

CREATE OR REPLACE PROCEDURE product_info(PRODUCT_NO IN CHAR)
AS
BEGIN
    for v_rec in (SELECT p.name, p.prod_id, p.description, p.unit_price, s.order_no
                  FROM PRODUCTS P, SUBORDERS S
                  WHERE p.prod_id = product_no )
    LOOP
      DBMS_OUTPUT.PUT_LINE('Product Code: ' || v_rec.prod_id 
      || ' Name: ' || v_rec.name 
      || ' Description: ' || v_rec.description
      || ' Price: ' || v_rec.unit_price
      || ' Order: ' || v_rec.odrer_no);
    END LOOP;
EXCEPTION
    WHEN no_data_found THEN 
    DBMS_OUTPUT.PUT_LINE ('Product number does not exist'); 
   WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE ('Operation failed  ' || 'SQLCODE: ' || SQLCODE); 
    ROLLBACK;
END; 
/

顺便说一下,您的查询在 PRODUCTS 和 SUBORDERS 之间没有连接,因此您的结果集将是一个产品(交叉连接)或两个表中的所有记录。几乎可以肯定你不想要那个。

此外,不在异常处理程序中重新引发异常是不好的做法(除了某些边缘情况)。像这样的玩具代码没关系,但不要养成坏习惯。