从显式游标调用函数

时间:2013-10-17 20:10:39

标签: sql oracle

我需要从这个PL / SQL块调用存储函数findtotalcarmodels。编写代码的方式不是我在生产中的方式,但它是一种“横向”思考的练习。

SET SERVEROUTPUT ON FORMAT WRAP SIZE 12000 
Declare 
v_model VARCHAR2(40);
v_cost NUMBER;
v_reg VARCHAR2(10);
v_carcategory VARCHAR2(40);
v_totalcars NUMBER;
v_count DATE;
v_maxcount DATE;
v_maxdept VARCHAR2(20);
cursor carcur IS 
SELECT * FROM i_car;
v_car carcur%ROWTYPE;
Cursor c_date (p_reg i_booking.registration%TYPE) IS
SELECT date_reserved
FROM i_booking
WHERE registration = p_reg;
v_date c_date%ROWTYPE;
Begin 
v_totalcars := findtotalcarmodels();
FOR v_car IN carcur LOOP
If v_cost <=50000 THEN v_carcategory := 'Budget Car';
End IF;
If v_cost BETWEEN 50000 AND 100000 THEN v_carcategory := 'Standard Car';
End IF;
If v_cost >100000 THEN v_carcategory := 'Premium Car';
End If;
FOR v_date IN c_date(v_car.registration) LOOP
v_count := v_count + 1;
END LOOP;
IF v_count > v_maxcount THEN
v_maxcount := v_count;
v_maxdept := v_car.registration;
END IF;
DBMS_OUTPUT.PUT_LINE('Registration:'|| ' '|| v_car.registration); 
DBMS_OUTPUT.PUT_LINE('Cost:'|| '$' ||v_car.Cost); 
DBMS_OUTPUT.PUT_LINE('Model Name:'|| ' '||v_car.model_name); 
DBMS_OUTPUT.PUT_LINE('Car Category:'|| ' '||v_carcategory);
DBMS_OUTPUT.PUT_LINE('Total number of Cars:'|| ' '||v_totalcars);
DBMS_OUTPUT.PUT_LINE('Most Recent Rental Date: '|| ' '||v_maxcount);
DBMS_OUTPUT.NEW_LINE; 
END LOOP; 
END;

我收到错误:

v_totalcars := findtotalcarmodels();
               *
ERROR at line 19: 
ORA-06550: line 19, column 16: 
PLS-00306: wrong number or types of arguments in call to 'FINDTOTALCARMODELS' 
ORA-06550: line 19, column 1: 
PL/SQL: Statement ignored 

我是否在正确的位置正确调用我的功能?

这是功能:

CREATE OR REPLACE Function findtotalcarmodels
(model_name_in IN varchar2)
RETURN NUMBER
IS
counter INTEGER := 0;
CURSOR car_count_cur IS
SELECT model_name FROM i_car WHERE model_name = model_name_in;
Rec_car_details car_count_cur%ROWTYPE;
BEGIN
OPEN car_count_cur;
LOOP
FETCH car_count_cur INTO Rec_car_details;
EXIT WHEN car_count_cur%NOTFOUND;
counter := counter + 1;
END LOOP;
CLOSE car_count_cur;
RETURN counter;
END;

1 个答案:

答案 0 :(得分:0)

好的,所以我不知道你为什么要用这个功能得到那个错误。该错误表示您没有为函数提供正确数量的参数。从显然不是正在发生的功能判断,或者它的功能不同。


你刚刚改变了函数调用;该函数需要一个参数,因此您在第一个修订版中的“错误”代码实际上是正确的。


然而,让我们把它放在一边一秒钟再看看你在做什么。

  1. 您的功能是对表的统计。不需要游标或循环,递增变量或任何东西。您可以将其简化为

    select count(*) from i_car where model_name = :model_name
    
  2. 您永远不会为变量v_countv_maxcount赋值,因此递增它们仍会导致NULL。无论如何,他们都是约会,所以增加它们有点奇怪。

  3. 您的光标c_date只是另一个计数;再一次不需要循环。

  4. 永远不会初始化model_name变量,因此您的函数不会返回结果。

  5. 有很多方法可以简化这个;虽然我会在这里猜几件事。将carcur光标更改为以下内容:

    select i.*
         , case cost
                when <= 50000 then 'Budget Car'
                when <= 100000 then 'Standard Car'
                else 'Premium Car'
           end as category
        , count(*) over ( partition by model_name ) as total_cars
     from i_cars
    

    这似乎可以删除您的IF语句和功能。然后,您可以通过在i_booking上执行外部联接来删除第二个循环(您需要在自己中添加主键):

    select i.*
         , case c.cost
                when <= 50000 then 'Budget Car'
                when <= 100000 then 'Standard Car'
                else 'Premium Car'
           end as category
        , count(distinct c.primary_key) 
             over ( partition by c.model_name ) as total_cars
        , count(b.date_reserved) 
             over ( partition by b.registration ) as reserved_ct
     from i_cars c
     left outer join i_booking b
       on c.registration = b.registration
    

    我不是百分之百确定最大的东西,因为它根本不清楚它被分配(它不是)但看起来好像你可能想要按模型等找到最大数量,在这种情况下你可以在上面的光标上使用子查询:

    select sub.*
         , max(total_cars) over () as max_cars
         , max(reserved_ct) over () as max_reserved
      from ( select i.*
                  , case c.cost
                         when <= 50000 then 'Budget Car'
                         when <= 100000 then 'Standard Car'
                         else 'Premium Car'
                    end as category
                 , count(distinct c.primary_key) 
                     over ( partition by c.model_name ) as total_cars
                 , count(b.date_reserved) 
                     over ( partition by b.registration ) as reserved_ct
              from i_cars c
              left outer join i_booking b
                on c.registration = b.registration
                   ) sub
    

    如果您需要输出它(很少需要),您可以遍历这个单一的SQL语句,它可以一次性为您提供所有内容:

    declare
    
      c_cursor is
        select sub.*
             , max(total_cars) over () as max_cars
             , max(reserved_ct) over () as max_reserved
          from ( select i.*
                      , case c.cost
                             when <= 50000 then 'Budget Car'
                             when <= 100000 then 'Standard Car'
                             else 'Premium Car'
                        end as category
                     , count(distinct c.primary_key) 
                         over ( partition by c.model_name ) as total_cars
                     , count(b.date_reserved) 
                         over ( partition by b.registration ) as reserved_ct
                  from i_cars c
                  left outer join i_booking b
                    on c.registration = b.registration
                       ) sub
    
                ;
    
    begin
    
       for i in c_cursor loop
          dbms_output.put_line(i.registration);
          dbms_output.put_line(i.cost);
          ...
       end loop;
    
    end;
    

    我将PL / SQL块和函数简化为单个SQL语句;它可能不是现场,因为有太多的未知因素,但值得为自己尝试。简单几乎总是更好。