PLSQL when trying to change value of length while loop gives error - oracle

In my pl sql while loop i try to change the length of a number, which also then changes the length of my value on which my while loop is based the while loop stops working. The code is as follows
CREATE OR REPLACE FUNCTION neemrest(restnumber number)
RETURN NUMBER
AS
partrest NUMBER;
afternumber NUMBER;
BEGIN
WHILE LENGTH(TO_CHAR(restnumber))>9 LOOP
partrest := TO_NUMBER(SUBSTR(restnumber,1,10));
afternumber := TO_NUMBER(SUBSTR(restnumber,11,20));
restnumber := partrest||afternumber;
END LOOP;
RETURN MOD(restnumber,64);
END;
Now by taking each step seperatly i found that the problem liest in the last line of the while loop
restnumber := partrest||afternumber;
Now my question how can i change the lenght of my number whilst not breaking the while loop since this is vital for my function. and the usage of my function

The problem you are running into is that you are trying to assign a value to a readonly parameter.
You should modify your function to be like this:
CREATE OR REPLACE FUNCTION neemrest(restnumber in out number)
RETURN NUMBER
AS
partrest NUMBER;
afternumber NUMBER;
BEGIN
WHILE LENGTH(TO_CHAR(restnumber))>9 LOOP
partrest := TO_NUMBER(SUBSTR(restnumber,1,10));
afternumber := TO_NUMBER(SUBSTR(restnumber,11,20));
restnumber := partrest||afternumber;
END LOOP;
RETURN MOD(restnumber,64);
END;

Related

inserting of data not happening in oracle

I am new to plsql.I have a table where i need to insert the data(some dummy data).So,i thought to use plsql block and using For loop it will insert the data automatically.The plsql block is runned successfully,but the data are stored as empty.The block I tried is:
declare
v_number1 number;
v_number2 number;
v_number3 number;
begin
For Lcntr IN 2..17
LOOP
v_number1 := v_number1+1;
v_number2 := v_number2+2;
v_number3 := v_number3+3;
Insert into stu.result(res_id,stu_id,eng,maths,science) values (stu.seq_no.NEXTVAL,Lcntr,v_number1,v_number2,v_number3);
END LOOP;
end;
But my table is loaded as:(please ignore first two row data,i inserted it manually):
The data for eng,maths,science is not being inserted.why it is happening so?
That's because your variables are NULL. NULL + 1 = NULL as well.
If you modify declaration to
v_number1 number := 0;
v_number2 number := 0;
v_number3 number := 0;
something might happen.

Can PL/SQL procedures call themselves recursively?

Using PL/SQL, it is possible to call a stored function from within that same function. This can be demonstrated with the following example:
CREATE OR REPLACE FUNCTION factorial(x in number)
RETURN number
IS
f number;
BEGIN
IF x = 0 THEN
f := 1;
ELSE
f := x * factorial(x-1);
END IF;
RETURN f;
END;
/
DECLARE
num number;
factorial number;
BEGIN
num := #
factorial := factorial(num);
dbms_output.put_line(' The factorial of '|| num || ' is ' || factorial);
END;
/
Can this be done using PL/SQL stored procedures as well?
Yes, you can write a procedure that calls itself recursively in PL/SQL. Here is an example - implementing the factorial.
With that said, don't ever write a procedure (or a function like yours) without error handling. If you don't understand why, change 5 to 5.3 in the anonymous block below, and you'll see why.
CODE window:
create or replace procedure fact ( x in number, x_fact out number )
as
begin
if x = 0 then x_fact := 1;
else fact(x-1, x_fact);
x_fact := x * x_fact;
end if;
end;
/
set serveroutput on
declare
z number;
begin
fact(5, z);
dbms_output.put_line(z);
end;
/
SCRIPT OUTPUT window (matching each "result" to the corresponding part of the code left as an exercise):
Procedure FACT compiled
PL/SQL procedure successfully completed.
120
You can certainly call PL/SQL functions recursively (with all the usual warnings about the dangers of doing so in any language!).
You are, however, going to run into trouble if you name a local variable the same as your function. You will, for example, get this error when you try to execute the block:
PLS-00222: no function with name 'FACTORIAL' exists in this scope

Extend table of varchar with a varchar

I'm trying to create a table of varchar array like this:
DECLARE
lna_poi_list fls_number_table := fls_number_table();
lsa_poi_list fls_varchar_table := fls_varchar_table();
ls_poi_list varchar;
BEGIN
FOR i IN 1..lna_poi_list.COUNT
LOOP
ls_poi_list := calling a function that returns a varchar and takes
lna_poi_list(i) as param;
lsa_poi_list.extend(ls_poi_list);
END LOOP
END;
After this I just want to return lsa_poi_list array but I'm getting some
character to number conversion error
Any ideas is much appreaciated
As documented, extend takes optional numeric arguments:
The EXTEND method has these forms:
EXTEND appends one null element to the collection.
EXTEND(n) appends n null elements to the collection.
EXTEND(n,i) appends n copies of the ith element to the collection.
To assign a new element, extend the collection, and then assign the value:
lsa_poi_list.extend;
lsa_poi_list(lsa_poi_list.COUNT) := ls_poi_list;
Referencing count means you're populating the last (new, null) element in the array.
If you're always adding one varhar (varchar2?) element for each element in the number array, you can size it once before the loop instead, which would be slightly more efficient, e.g:
DECLARE
lna_poi_list sys.odcinumberlist := sys.odcinumberlist();
lsa_poi_list sys.odcivarchar2list := sys.odcivarchar2list();
ls_poi_list varchar2(10);
BEGIN
lna_poi_list.extend(3);
lsa_poi_list.extend(lna_poi_list.COUNT);
FOR i IN 1..lna_poi_list.COUNT
LOOP
ls_poi_list := 'x'; -- from some function
lsa_poi_list(i) := ls_poi_list;
END LOOP;
END;
/
PL/SQL procedure successfully completed.

Calling a function in a before delete trigger

id like to call this function:
CREATE OR REPLACE PACKAGE orders_salary_manage2 AS
FUNCTION total_calc(p_order in NUMBER)
RETURN NUMBER;
END;
CREATE OR REPLACE PACKAGE BODY orders_salary_manage2 AS
tot_orders NUMBER;
FUNCTION total_calc(p_order in NUMBER)
RETURN NUMBER
IS
c_price product.unit_price%type;
c_prod_desc product.product_desc%type;
v_total_cost NUMBER := 0;
CURSOR c1 IS
SELECT product_desc, unit_price
FROM product
WHERE product_id IN (SELECT fk2_product_id
FROM order_line
WHERE fk1_order_id = p_order);
BEGIN
OPEN c1;
LOOP
FETCH c1 into c_prod_desc, c_price;
v_total_cost := v_total_cost + c_price;
EXIT WHEN c1%notfound;
END LOOP;
CLOSE c1;
return v_total_cost;
END;
from this trigger:
CREATE OR REPLACE TRIGGER trg_order_total
BEFORE DELETE ON placed_order
FOR EACH ROW
DECLARE
v_old_order NUMBER := :old.order_id;
BEGIN
total_calc(v_old_order);
END;
but i keep getting this error, note there is no error number just this:
Error at line 4: PL/SQL: Statement ignored
BEFORE DELETE ON placed_order
FOR EACH ROW
DECLARE
v_old_order NUMBER := :old.order_id;
BEGIN
im new to pl/sql and just not sure what is causing the problem. When a user deletes an order from the orders table the trigger should call the function to add up all the products on the order.
Thank you
(Considering your Package compiled with no errors) Use-
ret_val:= orders_salary_manage2.total_calc(v_old_order);
The ret_val must be a NUMBER since the package function total_calc returns a NUMBER. A function MUST always return its outcoume to a variable (like ret_val) depending on the type of the return value the data type of the variable must be declared.
The syntax to call Pacakaged Procedures and functions is -
<RETURN_VARIABLE> := PACKAGE_NAME.<FUNCTION_NAME>();
PACKAGE_NAME.<PROCEDURE_NAME>(); --Since Procedure never returns
Also note that if your package is in a different SCHEMA and has no PUBLIC SYNONYM then you will have to prefix the schema name like <SCHEMA>.PACKAGE_NAME.<FUNCTION_NAME>() (considering the calling schema has execute permissions on the package).
So,
CREATE OR REPLACE TRIGGER trg_order_total
BEFORE DELETE ON placed_order
FOR EACH ROW
DECLARE
v_old_order NUMBER := :old.order_id;
v_ret_val NUMBER := 0;
BEGIN
v_ret_val := orders_salary_manage2.total_calc(v_old_order);
--...Do stuff with v_ret_val
END;

Oracle, calling PL/SQL issues from within SQL-Plus file x.sql says my_function "may not be a function"

so simple, if I create my function as CREATE OR REPLACE FUNCTION MD5_ENCODE it will run smoothly, but if it stays anonymously within the SQL-Plus block as PL/SQL --> "may not be a function" error.
What is this Oracle "feature" again?
DECLARE
FUNCTION MD5_ENCODE(CLEARTEXT IN VARCHAR2) RETURN VARCHAR2 IS
CHK VARCHAR2(16);
HEX VARCHAR2(32);
I INTEGER;
C INTEGER;
H INTEGER;
BEGIN
IF CLEARTEXT IS NULL THEN
RETURN '';
ELSE
CHK := DBMS_OBFUSCATION_TOOLKIT.MD5(INPUT_STRING
=> CLEARTEXT);
FOR I IN 1 .. 16 LOOP
C := ASCII(SUBSTR(CHK, I, 1));
H := TRUNC(C / 16);
IF H >= 10 THEN
HEX := HEX || CHR(H + 55);
ELSE
HEX := HEX || CHR(H + 48);
END IF;
H := MOD(C, 16);
IF H >= 10 THEN
HEX := HEX || CHR(H + 55);
ELSE
HEX := HEX || CHR(H + 48);
END IF;
END LOOP;
RETURN HEX;
END IF;
END;
BEGIN
UPDATE ADDRESSES_T SET STREET = MD5ENCODE(STREET) ;
-- etc...
END
http://forums.oracle.com/forums/thread.jspa?threadID=245112
There are a number of things it could be.
My #1 candidate is, we can only use functions in SQL statements that are public i.e. declared in a package spec. This is the case even for SQL statements executed within the same Package Body. The reson is that SQL statements are executed by a different engine which can only see publicly declared functions.
Long story short, function must be defined in a package, like CREATE OR REPLACE FUNCTION MD5ENCODE(IN_TEXT IN VARCHAR2) RETURN VARCHAR2 IS ...
In order to call a function within a SQL statement, it needs to exist as a function object within the database. The SQL statement is parsed and executed separately from your PL/SQL code, so it doesn't have access to the locally defined function.
If you really don't want to create the function object, you could use a cursor to loop over the rows in the table, execute the function in a PL/SQL statement, and update each row as you go.
Your first problem is you have a typo.
FUNCTION MD5_ENCODE(CLEARTEXT IN
VARCHAR2) RETURN VARCHAR2 IS
versus
UPDATE ADDRESSES_T SET STREET =
MD5ENCODE(STREET) ;
You are missing the underscore in the function call in the update statement.
The next error you will encounter is :
PLS-00231: function 'MD5_ENCODE' may not be used in SQL
So you can simply assign the function results to a variable and use it in the Update statement.
As it mentioned above comments, this could be useful.
DECLARE
V NUMBER := 0;
FUNCTION GET_SQ(A NUMBER) RETURN NUMBER AS
BEGIN
RETURN A * A;
END;
BEGIN
V := GET_SQ(5);
--DBMS_OUTPUT.PUT_LINE(V);
UPDATE MYTABLE A SET A.XCOL = V;
END;

Resources