Loop for inserting range of values in plsql - oracle

I am trying to run following sql query to populate table, but am unable to run it... any ideas?
BEGIN
FOR n in 21500..21600 LOOP
if mod(n,2)=0
then
dbms_output.put_line(n||'even');
else
insert into port_mapping(APP,VERSION,BUSINESS,CRITICAL,SUPPORTED,TYPE,PORT,NOTE)
values("SDS","1","No","Yes","Yes","Server",n,"NA");
end if;
END LOOP;
COMMIT;
END;
I am getting the error
PL/SQL: ORA-00984: column not allowed here ORA-06550: line 8, column
7: PL/SQL: SQL Statement ignored

Your values are in double-quotes, which makes them (column) identifiers as far as Oracle is concerned. You need single quotes:
...
values('SDS','1','No','Yes','Yes','Server',n,'NA');
...
SQL Fiddle.
You don't need PL/SQL for this - you could use a simpler insert-into with a select-connect-by - but I'm not sure if you're doing this as an exercise.
insert into port_mapping (APP,VERSION,BUSINESS,CRITICAL,SUPPORTED,TYPE,
PORT,NOTE)
select 'SDS','1','No','Yes','Yes','Server',
21500 + (level * 2) - 1,'NA'
from dual
connect by level < 51;
SQL Fiddle.

Related

How to avoid this in PLSQL

I'm trying to create a function that looks like this
CREATE OR REPLACE FUNCTION get_sal
(dep_id IN departments.department_id%TYPE)
RETURN NUMBER IS
v_sal employees.salary%TYPE;
BEGIN
SELECT AVG(salary) INTO v_sal FROM Employees
WHERE department_id = dep_id;
RETURN v_sal;
END;
And I get an error that says
Error starting at line : 5 in command -
BEGIN
SELECT AVG(salary) INTO v_sal FROM Employees
WHERE department_id = dep_id;
RETURN v_sal;
END;
Error report -
ORA-06550: line 3, column 27:
PL/SQL: ORA-00904: "DEP_ID": invalid identifier
ORA-06550: line 2, column 5:
PL/SQL: SQL Statement ignored
ORA-06550: line 4, column 5:
PLS-00372: In a procedure, RETURN statement cannot contain an expression
ORA-06550: line 4, column 5:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
I got an example function from Oracle to see if it works but the same error appears.
There's nothing wrong with the function:
SQL> CREATE OR REPLACE FUNCTION get_sal (dep_id IN departments.department_id%TYPE)
2 RETURN NUMBER
3 IS
4 v_sal employees.salary%TYPE;
5 BEGIN
6 SELECT AVG (salary)
7 INTO v_sal
8 FROM Employees
9 WHERE department_id = dep_id;
10
11 RETURN v_sal;
12 END;
13 /
Function created.
SQL> select get_sal(10) from dual;
GET_SAL(10)
-----------
SQL>
as long as schema you're connected to contains DEPARTMENTS and EMPLOYEES tables with columns mentioned in that code. If you do not, then yes - expect errors.
As it seems you are using Sql Developer 20.4.0 as your SQL client, i guess the problem comes from the way you're compiling your SQL statement within this SQL client.
With SQL Developer, there is two ways to compile a SQL statement/execute a query. Selecting it in the editor and then click the green play button on the left as shown in the image below. The second way is to have only your statements in the editor and use the execute script button which is the second button to the right of the green play button. This one will execute all the statements in the editor.
I guess your error come from the use of the green play button while your cursor in the editor is on the statement but the statement is not fully selected or partially selected.
You can make SQL Developer complies with the behavior of Toad or have a custom behavior in this way in the SQL Developer options.

Need help understanding Cursor for loop

I am trying to write a code for every stock value that is $75 or more
add a "*" in the STK_FLAG column. my error repots are: Error report -
ORA-06550: line 15, column 21: PLS-00201: identifier 'STK_FLG' must be
declared ORA-06550: line 15, column 5: PL/SQL: SQL Statement ignored
ORA-06550: line 23, column 7: PL/SQL: ORA-00904: "STK_FLG": invalid
identifier ORA-06550: line 17, column 5: PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Blockquote
SET SERVEROUTPUT ON
DECLARE
CURSOR CURR
IS
SELECT STK_FLAG
FROM MM_MOVIE
WHERE MOVIE_VALUE * MOVIE_QTY >= 75
FOR UPDATE;
BEGIN
OPEN CURR;
LOOP
FETCH CURR INTO STK_FLG;
UPDATE
MM_MOVIE
SET
STK_FLG= '*'
WHERE
CURRENT OF CURR;
EXIT
WHEN CURR%notfound;
END LOOP;
Commit;
CLOSE CURR;
END;
/
You didn't declare a cursor variable (so there's nowhere you can put values returned by the cursor). Don't name it as column name; use a prefix, such as v_ or l_ or whichever you want.
Furthermore, in UPDATE you referenced a non-existent column. Cursor suggests its name is stk_flag, not stk_flg
Therefore, code that might be OK is
DECLARE
CURSOR curr IS
SELECT stk_flag
FROM mm_movie
WHERE movie_value * movie_qty >= 75
FOR UPDATE;
l_stk_flag mm_movie.stk_flag%TYPE; --> this
BEGIN
OPEN curr;
LOOP
FETCH curr INTO l_stk_flag;
EXIT WHEN curr%NOTFOUND;
UPDATE mm_movie
SET stk_flag = '*' --> this
WHERE CURRENT OF curr;
END LOOP;
COMMIT;
CLOSE curr;
END;
/
Why use a pl/sql anonymous block? Even if there is an "external" requirement for the functionality wrapped into pl/sql why use a cursor and loop? Using code that might be OK (from #Littlefoot) you retrieve a single column meeting your condition, iterate the resulting record set fetching that column but otherwise do nothing with it, and update a single row on every iteration of the loop with a literal value. SQL is designed for processing entire sets of rows at a time. Your processing can be done in a single update statement. Assuming there is an external requirement for a pl/sql block your code reduces to:
BEGIN
UPDATE mm_movie
SET stk_flag = '*'
WHERE movie_value * movie_qty >= 75;
COMMIT;
END;
Take away: When working with SQL stop thinking in terms of iterating (loops). Instead think of the commonality (set) of all objects to be processed. A different way of looking at problems and their corresponding solutions to be sure. Getting used to thinking that way will take some time, but in the long run your SQL and procedures will greatly improve because of it. Both in performance and clarity.

Trying to insert into a table while looping through pl SQL

I have a view that I need to loop through with all the inventory ids from another table. I keep receiving the following error: Error report -
ORA-06550: line 31, column 31:
PLS-00357: Table,View Or Sequence reference 'MISSINGINVENTORY' not allowed in this context
ORA-06550: line 31, column 2:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
This is my current code I am not sure what the problem would be? I ma fairly new to pl sql
DECLARE
CURSOR inventory_ids_c IS
SELECT DISTINCT fzrfbth_status status,
fzbfbth_inventory_id id
FROM fzbfbth#develop_sw,
fzrfbth#develop_sw
WHERE fzbfbth_inventory_id = fzrfbth_inventory_id
ORDER BY fzrfbth_status,
fzbfbth_inventory_id;
inventory_ids_rec inventory_ids_c%ROWTYPE;
BEGIN
OPEN inventory_ids_c;
FETCH inventory_ids_c INTO inventory_ids_rec;
LOOP
EXIT WHEN inventory_ids_c%NOTFOUND;
fzkfims.P_set_inventory_id#develop_sw(inventory_ids_rec.id);
DECLARE
CURSOR inventory_items IS
SELECT *
FROM fzvfims#develop_sw;
BEGIN
OPEN inventory_items;
LOOP
FETCH inventory_items INTO Missinginventory(last_inventory_date,
atype_title
,
owner, orgn_code, orgn_title, locn_code, room, bldg, sort_room,
ptag
,
manufacturer, model, serial_num, description, custodian, po,
acq_date,
amount,
ownership, schev_year, tag_type, inventory_id, condition,
asset_type
);
EXIT WHEN inventory_items%NOTFOUND;
END LOOP;
CLOSE inventory_items;
END;
END LOOP;
END;
It seems that you are trying to fetch from cursor directly into Missinginventory table (if it is a table). Well, that won't work. First fetch into cursor variables, then insert those variables into a table.
I don't know what this:
fzkfims.P_set_inventory_id#develop_sw(inventory_ids_rec.id);
does; looks like some procedure call. I guess it sets some kind of an "environment", but I don't know how it reflects to code you wrote.
Anyway: why do you use cursor loops? Can't you directly insert data into the table? That would be faster and - hopefully - simpler.
Also, if you declare something, do that at the same place, at the beginning of that PL/SQL procedure. If you scatter declarations all over your code, it is difficult to maintain it. Furthermore, see whether cursor FOR loops are an option as they are simpler to use - Oracle does a lot of things for you. How? Although you still have to write cursor's SELECT statement, you don't have to declare cursor variables, open cursor, fetch, take care about exiting the loop, close the cursor. I'll try to rewrite your code, have a look (as you can see, no declare section at all!).
begin
for cur_1 in (select distinct fzrfbth_status status,
fzbfbth_inventory_id id
from fzbfbth#develop_sw
join fzrfbth#develop_sw
on fzbfbth_inventory_id = fzrfbth_inventory_id
order by fzrfbth_status,
fzbfbth_inventory_id
)
loop
fzkfims.p_set_inventory_id#develop_sw(cur_1.id);
for cur_2 in (select *
from fzvfims#develop_sw
)
loop
-- I shortened it to just a few columns
insert into missinginventory
(last_inventory_date,
atype_title,
asset_type)
values (cur_2.last_inventory_date,
cur_2.atype_title,
cur_2.asset_type);
end loop;
end loop;
end;

Apex button and procedure

Im trying to create button in Apex which execute given procedure. As input values I gave two date fields called Poczatek and Koniec. The button should execute this procedure on submit. It perfectly works in Oracle, but throw a lot of errors in Apex.
set serveroutput on
create or replace procedure KORELACJA(:Poczatek, :Koniec)
IS
miasto VARCHAR(25);
korelacja NUMBER;
cursor c1 is
SELECT TEMP.nazwa, corr(TEMP.temperatura, WILGOTNOSC.wilg)
FROM TEMP INNER JOIN WILGOTNOSC
on TEMP.nazwa = WILGOTNOSC.nazwa
and TEMP.data = WILGOTNOSC.data
WHERE TEMP.data between to_date(:Poczatek, 'YYYY-MM-DD') and to_date(:Koniec, 'YYYY-MM-DD')
GROUP BY TEMP.nazwa;
BEGIN
DBMS_OUTPUT.put_line(RPAD('Miasto',10)||RPAD('Korelacja',10));
open c1;
FOR i IN 1..6
LOOP
commit;
fetch c1 into miasto, korelacja;
DBMS_OUTPUT.put_line(RPAD(miasto,10)||RPAD(korelacja,10));
END LOOP;
close c1;
END KORELACJA;
/
Errors look like this:
1 error has occurred
ORA-06550: line 2, column 5: PL/SQL: ORA-00922: missing or invalid option
ORA-06550: line 2, column 1: PL/SQL: SQL Statement ignored ORA-06550: line 6,
column 11: PLS-00103: Encountered the symbol "NUMBER" when expecting one of the
following: := . ( # % ; ORA-06550: line 9, column 18: PLS-00103: Encountered the symbol "JOIN" when
expecting one of the following: , ; for group having intersect minus order start
union where connect
Anyone knows the solution?
I'd suggest you to leave the procedure in the database; call it from Apex.
As you said that it works OK, I'm not going to examine the code. Just modify the first line:
create or replace procedure KORELACJA(par_Poczatek in date,
par_Koniec in date)
is ...
Then, in Apex process, call the procedure as
korelacja(:p1_poczatek, :p2_koniec);
Note that you might need to apply TO_DATE function to those items, using appropriate format mask, such as
korelacja(to_date(:p1_poczatek, 'dd.mm.yyyy',
to_date(:p1_koniec , 'dd.mm.yyyy');
If you insist on keeping the procedure in Apex' process (I wouldn't recommend it), the you don't need CREATE PROCEDURE but an anonymous PL/SQL block. It won't accept any parameters - use Apex items directly.
declare
miasto VARCHAR(25);
korelacja NUMBER;
cursor ...
WHERE TEMP.data between to_date(:p1_Poczatek, 'YYYY-MM-DD') ...
begin
...
end;

PLSQL ignore compilation error which is not an error

I came accross interesting error where I am not sure about best way how to fix it. Given following block:
DECLARE
v_column_exists number := 0;
host_column_exists number := 0;
i number;
BEGIN
Select count(*) into v_column_exists from user_tab_cols where column_name = 'CONNECTIONDESCRIPTION' and table_name = 'NODES';
if (v_column_exists = 1) then
Select count(*) into host_column_exists from user_tab_cols where column_name = 'HOST' and table_name = 'NODES';
if (host_column_exists = 0) then
execute immediate 'alter table NODES add (Host varchar2(255))';
for item in (select connectiondescription, code from nodes) loop
... LOOP STUFF ...
end loop;
end if;
end if;
END;
I get following result:
PL/SQL: ORA-00904: "CONNECTIONDESCRIPTION": invalid identifier
ORA-06550: line 40, column 20: PL/SQL: SQL Statement ignored
ORA-06550: line 41, column 20: PLS-00364: loop index variable 'ITEM'
use is invalid
any ideas how to get rid of this error? Problem is occuring when column NODES.CONNECTIONDESCRIPTION is not present in database, however in such case for loop won't execute in runtime. I would need to disable these errors, but haven't found any way to do it. I have tried using ALTER SESSION SET PLSQL_WARNINGS='DISABLE:00904', but it had no effect.
Thanks
Correct approach was to use another dynamic query which bulk collects items to an array and then loop through this array.

Resources