0

この 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;
4

1 に答える 1

0

さて、なぜその関数でそのエラーが発生するのかわかりません。このエラーは、関数に正しい数の引数を与えていないことを示しています。機能から判断すると、明らかに何が起こっているのか、または同じ機能ではありません。


関数呼び出しを変更しました。関数には引数が必要なため、最初のリビジョンにあった「間違った」コードは実際には正しいものでした。


ただし、それを少し脇に置いて、自分が何をしているかをもう一度見てみましょう.

  1. あなたの機能はテーブルのカウントです。カーソルやループ、インクリメント変数などは必要ありません。次のように単純化できます

    select count(*) from i_car where model_name = :model_name
    
  2. v_count変数または値を割り当てることはないため、v_maxcountそれらをインクリメントしても NULL になります。とにかく日付なので、インクリメントするのは少し奇妙です。

  3. カーソルc_dateは別のカウントです。繰り返しますが、ループは必要ありません。

  4. model_name変数は初期化されないため、関数は結果を返しません。

これを単純化する方法はたくさんあります。ここでいくつかのことを推測しますが。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 ステートメントと関数を削除できるようです。次に、外部結合を実行して 2 番目のループを削除できます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

割り当てられている場所がまったく明確ではないため(そうではない)、最大のものについて100%確実ではありませんが、モデルなどで最大数を見つけたいと思われるようです。その場合、サブを使用できます-上のカーソルに対するクエリ:

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 ブロックと関数を 1 つの SQL ステートメントに減らしました。不明な点が多いのでうまくいかないかもしれませんが、自分で試してみる価値はあります。ほとんどの場合、シンプルな方が優れています。

于 2013-10-17T20:44:41.817 に答える