How to insert dynamically through a variable in PL/SQL? - sql

Lets create a table first
create table test
(
id number,
name varchar2(20)
);
Now during insert, I want to hold the data into variable first & then dynamically pass the variable into the VALUES clause like this:
declare
v_data varchar2(50);
begin
v_data:='1,sunny';
execute immediate 'insert into test values(v_data)';
commit;
end;
But its showing some errors(Not enough values)...... plz help how to achieve this??

You need to use different variables for each value
declare
v_data1 number
v_data2 varchar2(50);
begin
v_data1 :=1
v_data2 = 'sunny';
insert into test values(v_data1,v_data2);
-- Alternatively insert into test (Name) values (v_data2);
commit;
end;

Table test has two columns. You're only inserting one and not naming which column it is hence "not enough values". So you need:
INSERT INTO test (name) VALUES (data)
or probably better is to put in an ID:
INSERT INTO test (id, name) VALUES (1, data)
or simply:
INSERT INTO test VALUES (1, data)
For this kind of thing though I would use a cursor rather than dynamic SQL (or even inline SQL).

The normal way to pass values into dynamic SQL statements is with bind variables like this:
declare
v_id integer;
v_name varchar2(50);
begin
v_id := 1;
v_name := 'sunny';
execute immediate
'insert into test (id, name) values(:b1, :b2)'
using v_id, v_name;
commit;
end;
That needs one variable per value.

Your approach works, but you need to adjust your query a little:
execute immediate 'insert into test values(' || v_data|| ')';
so that the contents of your v_data variable are actually inserted into the string, not the value "v_data" itself.

Related

Write an insert statement with select clause returning id in oracle

I am trying to write a query as follows:
Eg:
DECLARE
V_Output varchar(20):='';
BEGIN
INSERT INTO T(ID, MY_PK, NAME, VALUE)
(SELECT ID, NEXT_TRAN_VALUE('T'), NAME, VALUE FROM T WHERE MY_PK = 'NO0000000000013');
RETURNING MY_PK INTO V_Output;
DBMS_OUTPUT.PUT(V_Output);
END;
using below function
create or replace FUNCTION NEXT_TRAN_VALUE (field IN VARCHAR2) RETURN
VARCHAR2
IS
n_value VARCHAR2 (20);
P_APR VARCHAR2(3);
CURSOR rec_exists IS SELECT * FROM TRANSACTION_SEQ where SEQ_NAME = field ;
jk_seq_rec TRANSACTION_SEQ%ROWTYPE;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
SELECT LC_CODE into P_APR FROM LOCATION_CONFIG;
OPEN rec_exists;
FETCH rec_exists INTO jk_seq_rec;
IF rec_exists%FOUND THEN
UPDATE TRANSACTION_SEQ SET curr_value = curr_value + 1 WHERE SEQ_NAME = field;
COMMIT;
END IF;
--SELECT curr_value INTO n_value FROM TRANSACTION_SEQ WHERE SEQ_NAME = field;
END;
But, it shows error.
the select statement shall always return single statement to be inserted, so in my opinion it should return the my_pk of inserted row.
That won't work. RETURNING clause can't be used the way you're doing it, i.e.
insert into t (id, my_pk)
select some_id, your_function from ...
returning into v_output
but would work if you inserted VALUES, as
insert into t
values (id, your_function)
returning my_pk into v_output
It means that you'll either have to rewrite that code, or look at a workaround described in returning with insert..select article (written by Adrian Billington).
BTW, wouldn't an ordinary Oracle sequence suit your purpose? Won't be gapless, but would be simple & effective. Mind the performance when inserting huge amount of data, using your solution.
BTW #2, what's the purpose of the last line in your function? You never use N_VALUE.
I use Cursor to resolve the issue.

Inserting multipe values in PL/SQL

I am trying to insert values into a table using a for loop. I can't understand why it isnt working. I am a beginner. Any help would be appreciated.
create or replace procedure valueinput
as i number;
begin
for i in 1..10
loop
man_id number:=&Manager_Id;
man_fname varchar2(100):=&First_Name;
man_lname varchar2(100):=&Last_Name;
emp_id number:=&Employee_ID_Managed;
insert into managerinfo
values (man_id,man_fname,man_lname,emp_id);
i:=i+1;
end loop;
end;
You must declare your variables in the DECLARATION section of your PL/SQL block, right now you're trying to do it in the EXECUTION section.
Also, for a PL/SQL FOR..IN loop, you don't need to declare or increment your index.
Try something like this-
create or replace procedure valueinput
as
man_id number;
man_fname varchar2(100);
man_lname varchar2(100);
emp_id number;
begin
for i in 1..10
loop
man_id :=&Manager_Id;
man_fname :=&First_Name;
man_lname :=&Last_Name;
emp_id :=&Employee_ID_Managed;
insert into managerinfo
values (man_id,man_fname,man_lname,emp_id);
end loop;
end;
It would also be best practice to declare your variable types as the same as the table column that you're inserting into.
For example-
man_id managerinfo.manager_id%TYPE;

PLSQL Variable Insert

I send a parameter in my PLSQL function which is the name of the Table.
In my code, I want to insert into the table that is being received in the parameter.
When I type the insert statement
insert into TABLE_VARIABLE_NAME
VALUES (1, 2, 3);
It gives the error of Table Doesn't exist.
How can I use Table's Name as the parameter of the function?
Here is the full demo code you can try it and even the above hint is absolutely correct ,i just elaborated it more with insert values as varchar2 :-
create table td (valued varchar2(10));
create or replace procedure dhar_conn(tname varchar2)
as
begin
execute immediate 'insert into '||tname||' values(''1'')';
commit;
end;/
execute dhar_conn('td')
You'll need dynamic SQL with execute immediate.
execute immediate 'insert into ' || l_var_name || 'values (1,2,3)'

'insert into' in 'execute immediate' clause

Can you check this and tell me why I've got an error, please? How should it look? I have no idea what's wrong here. I need to create a table in a function, and in the same function insert data into this table:
create or replace
function new_tab ( pyt IN varchar2) return number
IS
a number;
b varchar2(20);
begin
a:= ROUND(dbms_random.value(1, 3));
b:='example';
-- This works perfect
execute immediate 'CREATE TABLE create_tmp_table'|| a ||'(i VARCHAR2(50))';
-- Here`s the problem
execute immediate 'insert into create_tmp_table'||a|| 'values ('|| b ||')';
exception
when others then
dbms_output.put_line('ERROR-'||SQLERRM);
return 0;
end;
My result is:
ERROR-ORA-00926: missing VALUES keyword. Process exited.
Where is the mistake?
As you are creating a dynamic insert command you have to create it as is. So you are missing the single quotes for the value that is varchar:
execute immediate
'insert into create_tmp_table'||a|| ' values ('''|| b ||''');';
^here ^and here
And a good suggestion for this type of error is to do some debug. On your case you could create a varchar2 variable and put your insert on it then you use the dbms_output.put_line to this variable. Then you will have your sql command that you can test direct on your database. Something like:
declare
sqlCommand varchar2(1000);
--define a and b
begin
--put some values in a and b
sqlCommand := 'insert into create_tmp_table'||a|| ' values ('''|| b ||''');';
dbms_output.put_line(sqlCommand);
end;
Then you will know what is wrong with the dynamic command.
execute immediate 'insert into TABLE'||a||' (COLUMN_NAME) values (:val)' using b;
This way you don't have to bother with escaping your values (SQL-injection hack) and correctly casting the type.
http://docs.oracle.com/cd/B13789_01/appdev.101/b10807/13_elems017.htm

PL/SQL Dynamic Loop Value

My goal is to keep a table which contains bind values and arguments, which will later be used by dbms_sql. The below pl/sql example is basic, it's purpose is to illustrate the issue I am having with recalling values from prior loop objects.
The table account_table holds acccount information
CREATE TABLE account_table (account number, name varchar2(100)));
INSERT INTO mytest
(account, name)
VALUES
(1 ,'Test');
COMMIT;
The table MYTEST holds bind information
CREATE TABLE mytest (bind_value varchar2(100));
INSERT INTO mytest (bind_value) VALUES ('i.account');
COMMIT;
DECLARE
v_sql VARCHAR2(4000) := NULL;
v_ret VARCHAR2(4000) := NULL;
BEGIN
FOR I IN (
SELECT account
FROM account_table
WHERE ROWNUM = 1
) LOOP
FOR REC IN (
SELECT *
FROM mytest
) LOOP
v_sql := 'SELECT ' || rec.bind_value || ' FROM dual';
EXECUTE IMMEDIATE v_sql INTO v_ret;
dbms_output.put_line ('Account: ' || v_ret);
END LOOP;
END LOOP;
END;
/
I cannot store the name i.account and later use the value that object. My idea was to use NDS; but, while the value of v_sql looks ok (it will read "Select i.account from dual"), an exception of invalid identifier would be raised on i.account. Is there a way to get the value of the object? We are using Oracle 11g2.
Thanks!
Dynamic SQL will not have the context of your PL/SQL block. You cannot use identifiers that are defined in the PL/SQL block in your dynamic SQL statement. So you cannot reference i.account and reference the loop that you have defined outside of the dynamic SQL statement. You could, of course, dynamically generate the entire PL/SQL block but dynamic PL/SQL is generally a pretty terrible approach-- it is very hard to get that sort of thing right.
If you are trying to use the value of i.account, however, you can do something like
v_sql := 'SELECT :1 FROM dual';
EXECUTE IMMEDIATE v_sql
INTO v_ret
USING i.account;
That doesn't appear to help you, though, if you want to get the string i.account from a table.
Are you always trying to access the same table with the same where clause, but just looking for a different column each time? If so, you could do this:
p_what_I_want := 'ACCOUNT';
--
SELECT decode(p_what_I_want
,'ACCOUNT', i.account
, 'OTHER_THING_1', i.other_thing_1
, 'OTHER_THING_2', i.other_thing_2
, 'OTHER_THING_1', i.default_thing) out_thing
INTO l_thing
FROM table;
The above statement is not dynamic but returns a different column on demand...