PL/SQL Inserting 1 row for each result in a select - plsql

I am writing a PL/SQL Procedure that performs a select based on input variables and then inserts a row for each result in the select. I am having trouble debugging what is wrong with my query due my newness to PL/SQL. I know this must be easy, but I am stuck here for some reason. Thanks for your help!
CREATE OR REPLACE PROCEDURE setup_name_map(ranking_id IN NUMBER, class_string IN VARCHAR2)
IS
BEGIN
FOR rec IN (SELECT NAME_ID FROM PRODUCT_NAMES WHERE NAME = class_string)
LOOP
EXECUTE IMMEDIATE 'INSERT INTO NAME_RANKING (NAME_ID, RANKING_ID) VALUES (' || rec.NAME_ID || ', ' || ranking_id || ')';
END LOOP;
END;
According to the Oracle Developer Compiler... 'NAME_ID' is an invalid identifier. I've tried putting it in quotes but no dice. It also complains that loop index variables 'REC' use is invalid. Any help is much appreciated.

There is no need for dynamic SQL here:
BEGIN
FOR rec IN (SELECT NAME_ID FROM PRODUCT_NAMES
WHERE NAME = class_string)
LOOP
INSERT INTO NAME_RANKING (NAME_ID, RANKING_ID)
VALUES (rec.NAME_ID, ranking_id);
END LOOP;
END;
Better still you can avoid a slow row-by-row cursor approach like this:
BEGIN
INSERT INTO NAME_RANKING (NAME_ID, RANKING_ID)
SELECT NAME_ID, ranking_id FROM PRODUCT_NAMES
WHERE NAME = class_string;
END;
If you really did need the dynamic SQL you should not be concatenating values into it, but using bind variables:
BEGIN
FOR rec IN (SELECT NAME_ID FROM PRODUCT_NAMES
WHERE NAME = class_string)
LOOP
EXECUTE IMMEDIATE 'INSERT INTO NAME_RANKING
(NAME_ID, RANKING_ID) VALUES (:b1, :b2)
USING rec.NAME_ID, ranking_id;
END LOOP;
END;

Related

I'm having trouble writing a cursor/loop. I'm not sure why it's not working

My code is here. I keep getting errors for the select statement. I've already created a waitlist table and a sequence. I inserted values into waitlist, however; I had to get the sname from the students table since waitlist does not have sname in the table. I'm trying to display RankingSid, Snum, sname, time(such as 1 pm or 2 pm).
create or replace procedure getWaiting(
p_callnum waitlist.callnum%type) as
cursor cwaiting is
select RankingSid, waitlist.snum, students.sname, to_char(time, 'hh AM')time
from waitlist, students
where p_callnum=callnum
and waitlist.snum=students.snum;
begin
For EachStudent in cwaiting loop
insert into TestTable values (EachStudent.RankingSid, Eachstudent.snum, EachStudent.sname, EachStudent.time);
dbms_output.put_line(eachstudent.rankingsid || eachstudent.snum || eachstudent.sname, eachstudent.time);
end loop;
end;
/
There are a number of syntax errors in your code, the biggest being your insert statement you need to reference your cursor variable for the insert in the same way that you did for the dbms_output. I do not have your table definitions to test the code but the below should be pretty close to what you need.
create or replace procedure getWaiting(
p_callnum waitlist.callnum%type) as
cursor cwaiting is
select RankingSid, waitlist.snum, students.sname, to_char(time, 'hh AM')time
from waitlist, students
where p_callnum=callnum
and waitlist.snum=students.snum;
begin
For EachStudent in cwaiting loop
insert into TestTable values (EachStudent.RankingSid, Eachstudent.snum, EachStudent.sname, EachStudent.time);
dbms_output.put_line(eachstudent.rankingsid || eachstudent.snum || eachstudent.sname || eachstudent.time);
end loop;
end;
/
I did it another way and would like to know how to change it..insert table wasn't working the other way. I was wondering if i'd have to create instead of inserting
create or replace procedure getWaiting(
p_callnum waitlist.callnum%type) as
begin
For eachRec in (select waitlist.rankingsid, students.snum, students.sname, to_char(time, 'hh:mi:ss AM') RequestedTime
from students, waitlist
where p_callnum=callnum
and students.snum=waitlist.snum
order by rankingsid)
Loop
dbms_output.put_line('Rank Number '|| eachRec.rankingsid ||' Student Name ' ||eachRec.sname ||' Student Number ' || eachRec.snum ||' Wait List Date ' || eachRec.RequestedTime);
end Loop;
end;
/

Execute immediate in netezza stored procedure is not inserting value to a table

When I am running this Netezza stored procedure, I am getting an error
attribute 'SOME_VALUE' not found
As per requirement I have to get value from one table (TABLE_A) and insert into another table (TABLE_B).
This is the procedure:
create or replace procedure my_proc()
returns boolean
execute as owner
language NZPLSQL
as
BEGIN_PROC
declare rec RECORD ;
BEGIN
for rec in SELECT * from TABLE_A loop
EXECUTE IMMEDIATE
'INSERT INTO TABLE_B(COLUMN_B)
values( '|| rec.COLUMN_A_OFTABLE_A || ')';
END LOOP;
END;
END_PROC;
execute my_proc()
Here below, I am able to insert a string. But I need to insert different value depending on other table as I mentioned above.
EXECUTE IMMEDIATE 'INSERT INTO TABLE_B(COLUMN_B) values( ''Y'');';
When building a string that you are going run EXECUTE IMMEDIATE against, you have be careful to have everything quoted properly. In your case it's thinking that it needs to treat SOME_VALUE as an attribute/column, and it can't any column with that name.
Wrap your column reference in quote_literal() and it will interpret the contents of your column and quote-escape it properly for you.
create or replace procedure my_proc()
returns boolean
execute as owner
language NZPLSQL
as
BEGIN_PROC
declare rec RECORD ;
BEGIN
for rec in SELECT * from TABLE_A loop
EXECUTE IMMEDIATE
'INSERT INTO TABLE_B(COLUMN_B)
values( '|| quote_literal(rec.COLUMN_A_OFTABLE_A) || ')';
END LOOP;
END;
END_PROC;
You can find some more information in the documentation here.
Note: I am assuming that you have some more complicated logic to implement in this stored procedure, because looping over row by row will be much, much slower that insert..select. Often by an order of magnitude.

PL/SQL How to iterate and update from an query inside a loop

I don't know how to iterate and update from a query result inside the loop. Is it possible to loop again from the query inside my first loop? Here is my code:
CREATE OR REPLACE PROCEDURE "myTEST" (sp_type in char)
IS
CURSOR c1 IS
SELECT SP_ID FROM CI_SP
WHERE SP_TYPE_CD = sp_type;
sp_id char(10);
item_id_eq CI_SP_EQ.ITEM_ID_EQ%type;
BEGIN
FOR sp_rec in c1
LOOP
DBMS_OUTPUT.PUT_LINE(sp_rec.sp_id);
SELECT ITEM_ID_EQ INTO item_id_eq FROM CI_SP_EQ
WHERE SP_ID = sp_rec.sp_id;
DBMS_OUTPUT.PUT_LINE('item id eq :' || item_id_eq);
-- iterate here for each item_id_eq
-- execute update for each item_id_eq also
END LOOP;
END myTEST;
Instead of looping twice you could just do a join between CI_SP & CI_SP_EQ and get it done in one shot:
CREATE OR REPLACE PROCEDURE "myTEST"(sp_type IN CHAR) IS
BEGIN
FOR item IN (SELECT item_id_eq
FROM ci_sp_eq JOIN ci_sp USING (sp_id)
WHERE sp_type_cd = sp_type) LOOP
-- do your stuff.
NULL;
END LOOP;
END mytest;
I think you wouldn't even need a PL/SQL block, just a simple UPDATE will do, but I don't exactly know what you're trying to do.
Some other comments:
Don't create objects enclosed in "quotes", the object name is now case sensitive. In your case, the compilation will fail because you've created procedure name as "myTEST" and end it with mytest, which Oracle will treat it as "MYTEST" and you'll get compile error because of syntax check fail
Use VARCHAR2 instead of CHAR, CHAR will pad spaces if the input doesn't match the length specifier and will lead to further problems

Parsing string in PL/SQL and insert values into database with RESTful web service

I am reading the values which I want to insert into database. I am reading them by lines. One line is something like this:
String line = "6, Ljubljana, Slovenija, 28";
Web service needs to separate values by comma and insert them into database. In PL/SQL language. How do I do that?
Here is some pl/sql that I have used to parse through delimited strings and then extract the individual words. You may have to mess with it a bit when using with the web service but it works fine when you are running it right in oracle.
declare
string_line varchar2(4000);
str_cnt number;
parse_pos_1 number := 1;
parse_pos_2 number;
parsed_string varchar2(4000);
begin
--counting the number of commas in the string so we know how many times to loop
select regexp_count(string_line, ',') into str_cnt from dual;
for i in 1..str_cnt + 1
loop
--grabbing the position of the comma
select regexp_instr(string_line, ',', parse_pos_1) into parse_pos_2 from dual;
--grabbing the individual words based of the comma positions using substr function
--handling the last loop
if i = str_cnt + 1 then
select substr(string_line, parse_pos_1, length(string_line)+1 - parse_pos_1) into parsed_string from dual;
execute immediate 'insert into your_table_name (your_column_name) values (' || parsed_string || ' )';
execute immediate 'commit';
--handles the rest
else
select substr(string_line, parse_pos_1, parse_pos2 - parse_pos_1) into parsed_string from dual;
execute immediate 'insert into your_table_name (your_column_name) values (' || parsed_string || ' )';
execute immediate 'commit';
end if;
parse_pos_1 := parse_pos_2+1;
end loop;
end;
I found an answer to that particular question. If you have similar values to those I posted for a question, like numbers, which look something like this:
String line = "145, 899";
This string is sent via POST request (RESTful web service, APEX). Now getting the values in PL/SQL and inserting them into table looks something like this:
DECLARE
val1 NUMBER;
val2 NUMBER;
str CLOB;
BEGIN
str := string_fnc.blob_to_clob(:body); // we have to convert body
val1 := TO_NUMBER(REGEXP_SUBSTR(str, '[^,]+', 1, 1));
val2 := TO_NUMBER(REGEXP_SUBSTR(str, '[^,]+', 1, 2));
// REGEXP_SUBSTR(source, pattern, start_position, nth_appearance)
INSERT INTO PRIMER VALUES (val1, val2);
END;
However, this is the method to insert line by line into database, so if you have large amount of rows in a file to insert, this isn't a way to do it. But here is the example which I requested. I hope it helps to someone.

How i can pass column names from variables in plsql update statement

DECLARE
v_name A.TRANSACTION_TYPE%TYPE :='SALARY';
v_salary A.SALARY%TYPE := 1000;
BEGIN
update A set v_name= v_salary where EMPID = 517;
-- PL/SQL: ORA-00904: "v_name": invalid identifier
--update A set SALARY = 1000 where EMPID = 517;
END;
/
My idea is to update table columns , but these column names are stored in variable. Is there any way to pass column names from variable ? Is there any options apart from Execute Immediate
Not sure if this will work in your situation, but I've written solutions where I wrote a script in SQLPlus and it "wrote" (using dbms_output.put_line or even just prompt) another script that did queries, and the columns/tables in those queries was determined by the logic in the SQLPlus script. Then I would execute as a script the output from my first script, and it would execute dynamically generated queries without ever needing execute immediate.
The following idea may work for multiple columns that are typed the same... As written, it will update all columns every time for a given record, but only the column specified by v_name will be changed to the value set in v_value; the other columns are simply updated to their existing value. The idea can be played with using DECODE, NVL or other similar conditional operators.
declare
v_name varchar2(20):= 'SAL';
v_value emptest.sal%TYPE := 5000;
begin
update emptest
set sal = ( select case when v_name = 'SAL' then v_value else sal end from dual),
comm = ( select case when v_name = 'COMM' then v_value else comm end from dual)
where empno = 7369;
commit;
end;

Resources