Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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.

like image 732
Craig Avatar asked Mar 29 '12 14:03

Craig


People also ask

What is select * from dual?

DUAL is a table automatically created by Oracle Database along with the data dictionary. DUAL is in the schema of the user SYS but is accessible by the name DUAL to all users. It has one column, DUMMY , defined to be VARCHAR2(1) , and contains one row with a value X .

How can I add values to a specific row in Oracle?

Single Row Insert You can add one row at a time to a table with the insert clause. This takes the form: insert into <table_name> ( col1, col2, ... ) values ( 'value1', 'value2', ... )

Can we use Rownum 1?

The first row selected has a ROWNUM of 1, the second has 2, and so on. You can use ROWNUM to limit the number of rows returned by a query, as in this example: SELECT * FROM employees WHERE ROWNUM < 10; If an ORDER BY clause follows ROWNUM in the same query, then the rows will be reordered by the ORDER BY clause.

What does select 1 from dual mean?

In your case, SELECT 1 FROM DUAL; will simply returns 1 . You need it because the INSERT ALL syntax demands a SELECT clause but you are not querying the input values from a table.


1 Answers

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; 
like image 160
Tony Andrews Avatar answered Oct 08 '22 20:10

Tony Andrews