PLS-00201: identifier 'USER INPUT' must be declared - sql

I'm getting the error "PLS-00201: identifier 'CHICAGO' must be declared" when I try to enter the user input at the prompt "Please enter the Region:" If I enter "CHICAGO" for example(without quotes of course) I get the PLS-00201 error. I can't figure out why- any ideas? Thanks in advance.
ACCEPT p_1 PROMPT 'PLEASE ENTER THE REGION:'
DECLARE
V_CHILD REGIONS.CHILD_NAME%TYPE := &p_1;
V_PARENT REGIONS.PARENT_NAME%TYPE;
CURSOR REG_CUR (p_child_name varchar2) IS
SELECT UPPER(CHILD_NAME)
FROM REGIONS
where CHILD_NAME = p_child_name;
BEGIN
OPEN REG_CUR (V_CHILD);
FETCH reg_cur INTO V_CHILD;
WHILE REG_CUR%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(V_CHILD);
FETCH reg_cur INTO V_CHILD;
END LOOP;
CLOSE REG_CUR;
END;

If you're expecting a string, you need to enclose the substitution variable in quotes when you use it:
V_CHILD REGIONS.CHILD_NAME%TYPE := '&p_1';
As it is, it's trying to interpret the substituted value as an identifier, i.e. another variable or a column name. So if you entered CHICAGO it would see:
V_CHILD REGIONS.CHILD_NAME%TYPE := CHICAGO;
and if you entered "CHICAGO":
V_CHILD REGIONS.CHILD_NAME%TYPE := "CHICAGO";
In Oracle using double quotes still indicates an identifier. You could in fact have entered 'CHICAGO', with quotes in your input, and it would have worked - but not ideal to have to remember to do that.
If you set verify on in SQL*Plus or SQL Developer then you can see the before and after of each substitution, which can help identitify things like this.

Related

Modifying a value in a table using PL/SQL

I have only just begun to learn procedures in SQL. I have hit a bit of a wall and can't seem to come to a fix. I am trying to create a procedure that will allow me to pass the item description and a percentage of how much I would like to increase that items price. This is the code I have got so far:
CREATE OR REPLACE PROCEDURE ADJUST_PRICE(
pItemDesc IN ITEM.ItemDesc%TYPE,
percentage IN NUMBER)
IS
pItemPrice NUMBER;
incAmt NUMBER;
BEGIN
SELECT itemprice into pItemPrice
FROM item WHERE itemdesc LIKE '%pItemDesc%';
incAmt := (pItemPrice*percentage)/100;
pItemPrice := incAmt + pItemPrice;
UPDATE Item
SET ItemPrice = pItemPrice
WHERE ItemDesc LIKE '%pItemDesc%';
END;
The procedure will compile but will not accept my calling block:
BEGIN
ADJUST_PRICE('%Dish%', 10);
END;
The error report I receive:
Error report -
ORA-01403: no data found
ORA-06512: at "S270131.ADJUST_PRICE", line 8
ORA-06512: at line 2
01403. 00000 - "no data found"
*Cause: No data was found from the objects.
*Action: There was no data from the objects which may be due to end of fetch.
Any help would be greatly appreciated, Thankyou.
It's not advisable to hit the ITEM table twice. Firstly, in a multi-user system, the details could have changed between your initial query and the update. Secondly it's inefficient, as it does twice as much work as it needs to.
I would simplify it to something like this:
create or replace procedure adjust_price
( p_itemdesc in item.itemdesc%type
, p_percentage in number )
as
l_increase_factor number := p_percentage/100 + 1;
begin
update item i
set i.itemprice = i.itemprice * l_increase_factor
where itemdesc like '%'||p_itemdesc||'%' escape '\';
end;
I have included an escape character to allow callers to treat wildcard characters % and _ as literals if they need to.
I've converted the percentage to a multiplication factor, so for example 50 percent becomes 1.5, rather than multiplying the price by the percentage, dividing by 100, and adding the original price, as I find that clearer arithmetically, but that's just my personal preference.
You used a p prefix for one of your two parameters (pItemDesc) and also for a local variable (pItemPrice). Code becomes confusing if variables are named like parameters and parameters are named like variables, so I recommend choosing one naming strategy and sticking with it.
Notice that code is easier to follow, work with and fix if it is neatly laid out, so I strongly recommend formatting like a programmer.
PL/SQL doesn't support this kind of string interpolation that you have in mind. But just use your input parameter as a bind variable instead:
SELECT ItemPrice
INTO pItemPrice
FROM Item
WHERE ItemDesc LIKE pItemDesc;
You'll still get NO_DATA_FOUND exceptions if your procedure doesn't find anything. But you don't actually need the extra SELECT. Just run the UPDATE directly:
UPDATE Item
SET ItemPrice = (ItemPrice * percentage) / 100 + ItemPrice
WHERE ItemDesc LIKE pItemDesc;

wrong number or types of arguments in call to procedure (PLS00306)

create or replace procedure flight_search(
v_source in flights.origin_ap%type,
v_destination in flights.destination_ap%type,
v_date in flights.depart_date%type,
v_flightid out flights.flightid%type,
v_fare out flights.fare%type)
is
cursor search_flight is SELECT flightid FROM flights
where v_source = origin_ap and v_destination = destination_ap and v_date =
depart_date;
begin
open search_flight;
loop
fetch search_flight into v_flightid;
exit when search_flight%NOTFOUND;
dbms_output.put_line('Leaves from - ' || v_source || '. Arrives at - ' ||
v_destination || '. Fare - ' || v_fare);
end loop;
close search_flight;
end;
executing by
execute flight_search('JFK', 'LHR', '11/25/18');
Getting wrong number or types of arguments in call to flight_search. I am assuming it has something to do with the flightid and fare variables.
Your procedure has 5 formal arguments, and your call only has 3. You need to supply somewhere for the out variables to go. As you seem to be using SQL*Plus or SQL Developer, judging by the execute, you can use bind variables and then print those out after the call:
variable l_flightid number;
variable l_fare number;
execute flight_search('JFK', 'LHR', date '2018-11-25', l_flightid, l_fare);
print l_flightid
I've also changed the third argument to an actual date, rather than a string which has to be implicitly converted to a date using your current session NLS settings. I've used a date literal, but you could also use to_date() with a string literal and a suitable format mask.
Incidentally, you aren't currently populating v_fare. so I haven't bothered printing that variable after the call; and it isn't obvious where it would come from. And you might want to consider using an implicit cursor loop instead of an explicit one.

Trying to use a where statement in cursor creation (PL/SQL)

I'm trying to create a block that accepts input from a prompt and uses that input to filter the result set for the cursor. Keep in mind I'm a novice here so I maybe making a very routine mistake, and thank you for your help. My current code is below.
Set serveroutput on
DECLARE
ACCEPT a PROMPT “Please Enter a Date, eg. Format - 01 or 30"
datev char
datev := &a;
CURSOR cur_day_cursor IS
SELECT Arrival_Date Adate
FROM FLIGHT
WHERE TO_CHAR(Arrival_Date, ‘DD’) = datev;
cur_day_cursor_var cur_day_cursor%ROWTYPE;
BEGIN
OPEN Cur_day_cursor;
LOOP
Fetch Cur_day_cursor
INTO cur_day_cursor_var;
EXIT WHEN cur_day_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE (cur_day_cursor_var.Adate);
END LOOP;
IF cur_day_cursor%ISOPEN THEN
CLOSE cur_day_cursor;
END IF;
END;
The where statement is causing my errors, so I was thinking that I may have to let the cursor collect all the data and then filter it when displaying, but I'm not sure if I can even do that.
The error I keep receiving ERROR at line 9:-
ORA-06550: line 9, column 1:
PLS-00103: Encountered the symbol "WHERE" when expecting one of the following:
begin function pragma procedure subtype type
current cursor delete
exists prior
I don't know exactly why Oracle is reporting the error at the WHERE. Sometimes the parser gets pretty confused by bad syntax and doesn't point to the real problem. You have several syntax errors before the cursor definition.
ACCEPT is a SQLPlus command, not a PL/SQL statement. Move your ACCEPT line above the DECLARE.
Also, your variable declaration and initialization are incorrect. The assignment should be part of the declaration line; you need to provide a length for the CHAR datatype; and the substitution value should be in quotes to be treated as a string. A valid version of your lines would be:
datev char(2) := '&a';
I ran the same query as above, and got the results perfectly fine.
You have few syntax as well as logical error which I corrected in your query. The syntax error(s) are -
datev char
datev := &a;
You can't do such an initialization in PL/SQL. You probably have to complete it in a single line like below -
datev char := &a;
The logical mistake(s) are -
Why use a CHAR variable to store data when you know that the value being returned is NUMBER.
You expect numbers from 1-31; then why do you choose the default size of char which as 1. It will fail if you provide a 2-digit number
Even if you increase the size of CHAR to CHAR(2), you will not get results when the users enters a number like 1 or 01, because for character wise comparison, '1' != '1 '(Mark the extra space at the end, because of char(2)); and also '1' != '01'.
The only solution for above is to use a NUMBER datatype.
Now here I am posting my query which is similar to your query, with a change of column name and table name. Please replace with your required names and try -
(Take care not to execute the ACCEPT....) with the PL/SQL block. It should be done in the SQL prompt first and then the other DECLARE section should be run.
--ACCEPT a NUMBER PROMPT 'Please Enter a Date, eg. Format - 01 or 30 :'
--Run the above line first in SQL Prompt and then execute the rest as whole
DECLARE
datev NUMBER(2) := &a;
CURSOR cur_day_cursor IS
SELECT Ename, HireDate Adate
FROM Emp
WHERE TO_CHAR(HireDate, 'D') = datev;
cur_day_cursor_var cur_day_cursor%ROWTYPE;
BEGIN
OPEN Cur_day_cursor;
LOOP
Fetch Cur_day_cursor
INTO cur_day_cursor_var;
EXIT WHEN cur_day_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE (cur_day_cursor_var.Adate);
END LOOP;
IF cur_day_cursor%ISOPEN THEN
CLOSE cur_day_cursor;
END IF;
END;
/
It appears that the problem is that the single-quotes around ‘DD’ aren't single-quotes. It looks like the code was created in an editor which changes apostrophes into those special "look kind of like single quotes but aren't really" characters. Replace the original version of the WHERE clause with the following:
WHERE TO_CHAR(Arrival_Date, 'DD') = datev;
and I suspect you'll be fine.
And get yourself a good code editor. :-)

Can't compare 2 strings - strange errors

I have this code in my procedure:
IF old_value_l = new_value_l THEN
dummy_val_l := 0;
ELSIF old_value_l != new_value_l THEN -- This is line 4019 mentioned in the error
-- some code here
END IF;
But it is throwing some strange errors:
ORA-01722: invalid number
ORA-06512: at "DBS.MONITORING", line 4019
ORA-06512: at line 12
It clearly says that the number is invalid, but wait a minute, what number?
Both old_value_l and new_value_l are declared as VARCHAR2(255 CHAR)
and here is how:
new_value_l history.new_value%TYPE;
old_value_l history.old_value%TYPE;
Why even when both of the variables are declared as VARCHAR2 it says that the number is invalid?
I know that I'm missing an extremely small part here, but I can't spot it or understand my mistake at this momment.
EDIT
Values I'm comparing:
new_value_l = 15 and old_value_l = 10
Code like this does not tell us they are numbers, it tells that first variable has a type like column new_value in history table, and the second variable has a type like old_value in history table.
new_value_l history.new_value%TYPE;
old_value_l history.old_value%TYPE;
So, you need to:
Ensure that both of these columns have the same datatype, VARCHAR2
Sometimes errors appear in a line, while actual error is in next or previous line, so you have to check them too
Try to check there is no spaces stored in values by using trim
...
ELSIF trim(old_value_l) != trim(new_value_l)
...
I think you have to handle null values too.
...
ELSIF trim(old_value_l) != trim(new_value_l)
...
It will be converted to a number automatically. So, you can test it as per the below:
select 1 from dual where '114' >120;
select 1 from dual where '125' >120;
You'd better check whether each value has some characters which cannot be converted to a number, such as CRLF.

Different Regional Setting Different Format Float in Delphi

I want to make Insert SQL Statement in Delphi using BDE Paradox which is
value_a := 0,123;
value_b := 0,234;
value_c := 0,345;
insert into mst_value values (value_a, value_b, value_c);
it shows the error like 'invalid SQL parameter' after debugging, it shows that the sql complete syntax like
insert into mst_value values (0,123, 0,234, 0,345)
which is supposed to be dot but comma in the decimal, so I format it using formatfloat('#.###, value_a), ...` it still using comma, after change the regional setting on Control Panel to English, the SQL parameter is correct, this is because the currency or number format there is just like 123,123,123.00, so, how can I format the decimal number but from another country e.g Indonesia with the format like 123,123,123,123.00 not 123.123.123,00. thanks before...
Try in this way, before calling the formatFloat function, you
can set appropriate value for Delphi's variable ThousandsSeparator and DecimalSeparator :
FormatFloat( "$##.000", value_a );
how do you make string like that ?
"insert into mst_value values (0,123, 0,234, 0,345) "
It is aking for SQL Injection, that wouldallow anyone to break into your program.
Use TQuery.Params instead, with strict datatype checking.
More reasoning on this in comments at http://issuetracker.delphi-jedi.org/view.php?id=5916
I am with Arioch on this. You should use a parameterized query instead. That will let the DB engine handle the formatting for you, eg:
value_a := 0,123;
value_b := 0,234;
value_c := 0,345;
Query.SQL.Text := 'insert into mst_value values (:value_a, :value_b, :value_c)';
Query.ParamByName('value_a').AsFloat := value_a;
Query.ParamByName('value_a').AsFloat := value_b;
Query.ParamByName('value_a').AsFloat := value_c;
Query.ExecSQL;