PLS-00394: Wrong number of values in the INTO list of a fetch statement - sql

This is my attempt in creating a cursor in a stored procedure
--Second Stored Procedure--
CREATE OR REPLACE PROCEDURE sp_GetDiscountedRate (DiscountCode IN
VARCHAR2,Percentage IN NUMBER, ReserveDate IN DATE)
IS --Code declaration section--
--variables to store column values returned from select into
pPassengerID VARCHAR2(10);
pFirst VARCHAR2(20);
pMiddle VARCHAR2(20);
pLast VARCHAR2(20);
pPassengerType CHAR (1);
uUSMilitaryID VARCHAR (8);
uMilitaryBranch VARCHAR2 (20);
uMilitaryDiscountCode VARCHAR2(8);
rFlightNumber VARCHAR2(6);
rReservationCost NUMBER(6);
rReservationDate DATE;
--Declare Cursor
CURSOR cur_USMilitary IS
--Query cursor will point to results
SELECT P.PassengerID, P.First, P.Middle, P.Last, P.PassengerType,
U.USMilitaryID, U.MilitaryBranch,
U.MilitaryDiscountCode, R.FlightNumber, R.ReservationCost,
R.ReservationDate,
CASE U.MilitaryDiscountCode WHEN DiscountCode THEN
Percentage*R.ReservationCost
ELSE R.ReservationCost END "REVISED_RESERVATION_COST"
FROM PASSENGER P, US_Military U, RESERVATION R
WHERE P.PassengerID = U.MPassengerID
AND P.PassengerID = R.PassengerID
AND U.MilitaryDiscountCode = DiscountCode
AND R.ReservationDate = ReserveDate;
--Start Execution section--
BEGIN
--Open Cursor
OPEN cur_USMilitary; -- open cursor for use
--loop to display each record returned by cursor
--Use PL/SQL language control or loop to display each record pointed by cursor
LOOP
--Fetch cursor data
FETCH cur_USMilitary INTO pPassengerID,
pFirst,pMiddle,pLast,pPassengerType,
uUSMilitaryID,uMilitaryBranch,uMilitaryDiscountCode,rFlightNumber,
rReservationCost,rReservationDate;
EXIT WHEN cur_USMilitary%NOTFOUND;
--Display each record
--Displaying the results
DBMS_OUTPUT.PUT_LINE ('CUSTOMER INFORMATION: ');
DBMS_OUTPUT.PUT_LINE ('The PassengerID is: ' ||pPassengerID);
DBMS_OUTPUT.PUT_LINE ('First Name of passenger is: ' ||pFirst);
DBMS_OUTPUT.PUT_LINE ('Middle Name of passenger is: ' ||pMiddle);
DBMS_OUTPUT.PUT_LINE ('Last Name of passenger is: ' ||pLast);
DBMS_OUTPUT.PUT_LINE ('Passenger Type of customer is: ' ||pPassengerType);
DBMS_OUTPUT.PUT_LINE ('US Military ID of Passenger is: ' ||uUSMilitaryID);
DBMS_OUTPUT.PUT_LINE ('Military Branch of passenger is: ' ||uMilitaryBranch);
DBMS_OUTPUT.PUT_LINE ('Military Discount code of passenger is: ' ||uMilitaryDiscountCode);
DBMS_OUTPUT.PUT_LINE ('Flight number of passenger is: ' ||rFlightNumber);
DBMS_OUTPUT.PUT_LINE ('Reservation Cost of passenger is: ' ||rReservationCost);
DBMS_OUTPUT.PUT_LINE ('Reservation Date of passenger is: ' ||rReservationDate);
END LOOP;
CLOSE cur_USMilitary; --close cursor
END sp_GetDiscountedRate;
I get this error:
Error(36,9): PL/SQL: SQL Statement ignored
Error(36,9): PLS-00394: wrong number of values in the INTO list of a FETCH statement
I fully understand the error. I checked the number of columns and it looks like to me that they match the number of columns within the query. I've also checked the datatypes to make sure it was correct.

You have
12 columns in your cursor's SELECT part
but
11 columns in FETCH statement part
, i observe
CASE U.MilitaryDiscountCode WHEN DiscountCode THEN
Percentage*R.ReservationCost
ELSE R.ReservationCost END "REVISED_RESERVATION_COST"
part is missing in FETCH( or should be omitted in the SELECT part ).
It also represents a column, and it spoils 1-1 correspondence, which yields that error.

This is what happens when you overcomplicate things, I'm afraid. I don't see any need for all those variables and the corresponding fetch into that is hard to keep in sync. Why not just:
create or replace procedure sp_getdiscountedrate
( discountcode in varchar2
, percentage in number
, reservedate in date )
is
begin
for r in (
select p.passengerid
, p.first
, p.middle
, p.last
, p.passengertype
, u.usmilitaryid
, u.militarybranch
, u.militarydiscountcode
, r.flightnumber
, r.reservationcost
, r.reservationdate
, case u.militarydiscountcode
when discountcode then percentage * r.reservationcost
else r.reservationcost
end as revised_reservation_cost
from passenger p
join us_military u
on u.mpassengerid = p.passengerid
join reservation r
on r.passengerid = p.passengerid
and r.discountcode = u.militarydiscountcode
and r.reservedate = r.reservationdate
)
loop
dbms_output.put_line('CUSTOMER INFORMATION:');
dbms_output.put_line('The PassengerID is: ' || r.passengerid);
dbms_output.put_line('First Name of passenger is: ' || r.first);
dbms_output.put_line('Middle Name of passenger is: ' || r.middle);
dbms_output.put_line('Last Name of passenger is: ' || r.last);
dbms_output.put_line('Passenger Type of customer is: ' || r.passengertype);
dbms_output.put_line('US Military ID of Passenger is: ' || r.usmilitaryid);
dbms_output.put_line('Military Branch of passenger is: ' || r.militarybranch);
dbms_output.put_line('Military Discount code of passenger is: ' || r.militarydiscountcode);
dbms_output.put_line('Flight number of passenger is: ' || r.flightnumber);
dbms_output.put_line('Reservation Cost of passenger is: ' || r.reservationcost);
dbms_output.put_line('Reservation Date of passenger is: ' || r.reservationdate);
dbms_output.put_line('Revised reservation cost is: ' || r.revised_reservation_cost);
end loop;
end sp_getdiscountedrate;
(Untested)

You go through all the trouble of calculating "REVISED_RESERVATION_COST", and then you don't read it from the cursor.
No wonder Oracle is complaining. You need a variable for this column as well.
I would also advise you to learn to use modern, proper, explicit JOIN syntax.

Related

SQL Invalid Identifier when using bind variable

Using my anonymous block I have written below, the bind variable is giving me the error: I've pasted a picture of the table below.
edit: ETHI1022 is the input I'm giving for the CORID
v_corid CHAR(8) := ETHI1022;
*
ERROR at line 3:
ORA-06550: line 3, column 24:
PLS-00201: identifier 'ETHI1022' must be declared
ORA-06550: line 0, column 0:
PL/SQL: Compilation unit analysis terminated
I realize my inner join is most likely messed up like no other. I'm trying to learn this stuff and am having a very hard time learning how taking values from the select statement and placing them into the variables in the declare section works.
DECLARE
v_marstuid MARKS.STUID%TYPE;
v_corid CHAR(8) := &corid;
v_avgmark NUMBER(2);
v_maxmark NUMBER(2);
v_minmark NUMBER(2);
v_cordesc VARCHAR2(255);
ex_CourseNotFound EXCEPTION;
BEGIN
SELECT Count(M.stuid),
M.corid,
Avg(M.mark),
Max(M.mark),
Min(M.mark),
C.descript
INTO v_marstuid, v_corid, v_avgmark, v_maxmark,
v_minmark, v_cordesc
FROM marks M
inner join courses C
ON M.corid = C.corid
WHERE C.corid = v_corid;
dbms_output.Put_line (v_corid
|| ' - '
|| v_cordesc);
dbms_output.Put_line ('Course Stats: ');
dbms_output.Put_line ('Number of students: '
|| v_marstuid);
dbms_output.Put_line ('Average: '
|| v_avgmark);
dbms_output.Put_line ('Marks Range: ');
dbms_output.Put_line ('High: '
|| v_maxmark);
dbms_output.Put_line ('Low: '
|| v_minmark);
EXCEPTION
WHEN ex_CourseNotFound THEN
DBMS_OUTPUT.PUT_LINE(v_corcode || ' Does not exist.');
END;
/
[Table used]
Instead of ETHI1022 it should be 'ETHI1022'. Your inner join is fine. From where you are getting value of corid. Make it of type varchar/string or something like that.
Or you might try v_corid CHAR(8) := ''''||&corid||'''';

PL/SQL: Cursor doubles the last record from the table

I created the following PL/SQL anonymous block. The cursor below retrieves data from the select statement:
select mod_benutzer, count(*)
from dok_auspraegung
where parent_objekt_id = 1093
group by mod_benutzer;
This statement displays exactly two records:
DDMS_USER | 8
HU2MAMU | 14
But when I want to display these two records by cursor, it displays "HU2MAMU|14" two times like below:
Modifications:
DDMS_USER, 8x
HU2MAMU, 14x
HU2MAMU, 14x
declare
my_exception_1 exception;
var_parent_objekt_id dok_auspraegung.parent_objekt_id%TYPE := 1093;
var_date varchar(30);
var_mod_benutzer varchar2(10);
var_benutzer_modifs number;
cursor cursor_dok_auspraegung
is select mod_benutzer, count(*) from dok_auspraegung
where parent_objekt_id = 10935797565
group by mod_benutzer;
begin
select distinct to_char(mod_datum,'YYYY-MON-DD') into var_date from dok_auspraegung where parent_objekt_id = var_parent_objekt_id;
IF var_date is not null THEN
dbms_output.put_line('Parent Object ID' || ': ' || var_parent_objekt_id);
dbms_output.put_line('Date: ' || ' ' || var_date);
ELSE RAISE my_exception_1;
END IF;
open cursor_dok_auspraegung;
dbms_output.put_line('Modifications:');
loop
fetch cursor_dok_auspraegung into var_mod_benutzer, var_benutzer_modifs;
dbms_output.put(var_mod_benutzer);
dbms_output.put_line(', ' || var_benutzer_modifs || 'x');
exit when cursor_dok_auspraegung%notfound;
end loop;
dbms_output.put_line(cursor_dok_auspraegung%rowcount);
close cursor_dok_auspraegung;
exception
when NO_DATA_FOUND then
dbms_output.put_line('Parent Object ID not found!');
when my_exception_1 then
dbms_output.put_line('');
end;
What is the reason of that?
Because exiting from the cursor occurs after printing the value of the variables in the current case, this repeats the last value to be printed. So, it should occur before printing as follows
loop
fetch cursor_dok_auspraegung into var_mod_benutzer, var_benutzer_modifs;
exit when cursor_dok_auspraegung%notfound;
dbms_output.put(var_mod_benutzer);
dbms_output.put_line(', ' || var_benutzer_modifs || 'x');
end loop;

Oracle APEX 4.2 Custom search in classic report

I am using Oracle APEX 4.2. I want to implement a search function in my classic report. I have a working code that retrieve data and the search function works perfectly. But when I want to use an order by clause inside that code I get "no data found" how can I implement an order by clause into this code so my report will be sorted correctly and the search function will still work correctly.
Here is the working code below that allows you to search the classic report:
declare
a_query varchar2(5000);
this_strin varchar2(50);
begin
a_query := 'select flight_nmbr, sequence_nmbr'||
'from flights '||
'where sequence_nmbr >= 0'||
'and data_version_name = '''||
:P3_DATA_VERSION || '''';
if :P3_SEARCH_NUMBER is not null then
if instr(:P3_SEARCH_NUMBER, '%') > 0 then
this_strin := :P3_SEARCH_NUMBER;
else
this_strin := '%'||:P3_SEARCH_NUMBER||'%';
end if;
a_query := a_query||chr(10)||
' and flight_nmbr like '''|| upper(this_strin) ||'''';
end if;
return a_query;
end;
Here is same piece of code that does says "no data found" when I add the order by clause to the query:
declare
a_query varchar2(5000);
this_strin varchar2(50);
begin
a_query := 'select flight_nmbr, sequence_nmbr'||
'from flights '||
'where sequence_nmbr >= 0'||
'and data_version_name = '''||
'order by sequence_nmbr 1'|| ------------------Order by clause
:P3_DATA_VERSION || '''';
if :P3_SEARCH_NUMBER is not null then
if instr(:P3_SEARCH_NUMBER, '%') > 0 then
this_strin := :P3_SEARCH_NUMBER;
else
this_strin := '%'||:P3_SEARCH_NUMBER||'%';
end if;
a_query := a_query||chr(10)||
' and flight_nmbr like '''|| upper(this_strin) ||'''';
end if;
return a_query;
end;
Obviously, your problem is here:
begin
a_query := 'select flight_nmbr, sequence_nmbr'||
'from flights '||
'where sequence_nmbr >= 0'||
'and data_version_name = '''|| -- double qoute!!!
'order by sequence_nmbr 1'|| ------------------Order by clause
:P3_DATA_VERSION || '''';
Due to that redundant double quote, your resulting query looks like this:
select flight_nmbr, sequence_nmbr
from flights
where sequence_nmbr >= 0
and data_version_name = 'order by sequence_nmbr 1<value of P3_DATA_VERSION item>';
As soon as the table has no value order by sequence_nmbr 1 in the column data_version_name, the query returns no rows.
The second problem you will encounter when you'll fix this one is here:
if :P3_SEARCH_NUMBER is not null then
When this statement will be true, you will get a query where the condition and flight_nmbr like ... stands after the ORDER BY clause.
By the way, I would recommend you write a simple query for the report. Generating SQL dynamically leads to such errors and costs you a performance decrease also.
Not related to your question, but - why don't you switch to interactive report? It offers much more than a classic report, don't you think?
As of your problem: if you look at query that fails, its SELECT looks like this (I've removed single quotes):
and data_version_name = ||
order by sequence_nmbr 1 || ------------------Order by clause
:P3_DATA_VERSION ||
and flight_nmbr like upper(this_strin)
Either you didn't post actual code, or this is generally wrong - I hope you see what is wrong here. ORDER BY should be the last clause. Besides, what's that "1" doing at the end of the ORDER BY?
I'd suggest you to first display contents of the A_QUERY, check whether it works OK (in SQL*Plus, TOAD, SQL Developer or any other tool you use), and - once you're satisfied with it - let it work in Apex.

For loop using VARCHAR2

I'm trying to display the info for each student using this code
DECLARE
CURSOR cursor1 IS SELECT STUDENTNAME, COURSEID, COURSEDESCRIPTION, COURSECREDITS, GRADE
FROM STUDENTINFO;
S_NAME STUDENTINFO.STUDENTNAME%TYPE;
S_COURSEID STUDENTINFO.COURSEID%TYPE;
S_COURSEDESCRIPTION STUDENTINFO.COURSEDESCRIPTION%TYPE;
S_COURSECREDITS STUDENTINFO.COURSECREDITS%TYPE;
S_GRADE STUDENTINFO.GRADE%TYPE;
BEGIN
OPEN CURSOR1;
LOOP
FETCH CURSOR1 INTO S_NAME, S_COURSEID, S_COURSEDESCRIPTION, S_COURSECREDITS, S_GRADE;
EXIT WHEN cursor1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Student Name: ' || S_NAME);
DBMS_OUTPUT.PUT_LINE(S_COURSEID || S_COURSEDESCRIPTION || S_COURSECREDITS || S_GRADE);
DBMS_OUTPUT.PUT_LINE(CHR(10));
END LOOP;
CLOSE CURSOR1;
END;
/
My output should be similar to
Student Name: John
CMIS 101 Intro to Info. Systems 3 B
CMIS 301 System Analysis 3 C
CMIS 451 Client/Server Systems 3 C
I'm pretty sure I should be using a for loop which I created
DECLARE
CURSOR cursor2 IS SELECT STUDENTNAME, COURSEID, COURSEDESCRIPTION, COURSECREDITS, GRADE
FROM STUDENTINFO;
search_student STUDENTINFO.STUDENTNAME%TYPE;
BEGIN
FOR v_Record IN cursor2
LOOP
IF v_Record.STUDENTNAME = &SEARCH_STUDENT THEN
DBMS_OUTPUT.PUT_LINE('Student Name: ' || STUDENTNAME);
DBMS_OUTPUT.PUT_LINE(COURSEID || COURSEDESCRIPTION || COURSECREDITS || GRADE);
DBMS_OUTPUT.PUT_LINE(CHR(10));
END IF;
END LOOP;
END;
/
However, when I type in a name for search_student, I'm just given the error
Identifier "insertnamehere"
Can I not use VARCHAR2 when searching? Is it only usable with numbers?
There are a few issues with your code.
For a start, why use PL/SQL to do this? You should just use a SQL statement directly. I'm going to assume that this is a homework question though (*sigh* - surely there are better examples to use?!).
1. IF v_Record.STUDENTNAME = &SEARCH_STUDENT - when you pass in a value for search_student, the client replaces the term &search_student. So, either you must ensure that the single quotes to specify the studentname is a string when you define the search_student (ie. when prompted for search_student you enter "'SomeName'") OR put the single quotes around the &SEARCH_STUDENT - ie. IF v_Record.STUDENTNAME = '&SEARCH_STUDENT'
2. When referencing the fields returned by the cursor in the for loop, you need to reference the record that the values were fetched into. Therefore DBMS_OUTPUT.PUT_LINE('Student Name: ' || STUDENTNAME); should be DBMS_OUTPUT.PUT_LINE('Student Name: ' || v_Record.STUDENTNAME);
3. Finally, if you're looking to output a single student record at a time, put the filter in the cursor, not in the loop.

I'm trying to use a variable from a cursor in the select statement of another cursor in pl/sql

I need to run a query that finds me the first 20 vehicles that are as close to another vehicle with specific terms. I'm writing this in SQL Developer on an oracle database.
Here's what I have so far:
DECLARE
TYPE cur_type IS REF CURSOR;
CURSOR lost_vehicles_cur IS
select
v.vin,
V.VEHICLE_ID
from d_vehicles V
where v.system_id =4 ;
make_cur cur_type;
l_cur_string VARCHAR2(2000);
l_make <type>;
l_model <type>;
l_vin <type>;
BEGIN
FOR vehicle IN lost_vehicles_cur LOOP
dbms_output.put_line('lost vehicle is '|| vehicle.vehicle_id);
l_cur_string := 'SELECT make_name, model_name,vin FROM vehicles where make=(select make from vehicles where vehicle_id= '
|| vehicle.vehicle_id || 'and rownum<=20 and system_id=3 and vehicle_status_id in (13,14) ';
OPEN make_cur FOR l_cur_string;
LOOP
FETCH make_cur INTO l_make, l_model, L_vin;
EXIT WHEN make_cur%NOTFOUND;
dbms_output.put_line('Related vehicles are ' || l_make || l_model || L_vin);
END LOOP;
CLOSE make_cur;
END LOOP;
END;
I used a previous answer to get to this however I get the following error when I run this:
ORA-06550: line 32, column 13: PLS-00103: Encountered the symbol "<" when expecting one of the following: constant exception table long double ref char time timestamp interval date binary national character nchar 06550. 00000 - "line %s, column %s:\n%s" *Cause: Usually a PL/SQL compilation error. –
You have to use parametrized cursor or dbms_sql:
DECLARE
TYPE cur_type IS REF CURSOR;
CURSOR lost_vehicles_cur IS
select
v.vin,
V.VEHICLE_ID
from d_vehicles V
where v.system_id =4 ;
cursor l_cur (ip_id in d_vehicles.VEHICLE_ID%type)
SELECT make_name, model_name,vin
FROM vehicles
where make in (select make
from vehicles
where vehicle_id= ip_id
and rownum<=20
and system_id=3
and vehicle_status_id in (13,14));
make_cur cur_type;
l_cur_string VARCHAR2(2000);
l_make <type>;
l_model <type>;
l_vin <type>;
BEGIN
FOR vehicle IN lost_vehicles_cur LOOP
dbms_output.put_line('lost vehicle is '|| vehicle.vehicle_id);
OPEN make_cur FOR l_cur (vehicle.vehicle_id);
LOOP
FETCH make_cur INTO l_make, l_model, L_vin;
EXIT WHEN make_cur%NOTFOUND;
dbms_output.put_line('Related vehicles are ' || l_make || l_model || L_vin);
END LOOP;
CLOSE make_cur;
END LOOP;
END;