Using bind variable as table name in Alter table script - constraints

FOR k in c2 LOOP
l_sql := 'ALTER TABLE :TABLE_NAME DISABLE CONSTRAINT
:CONSTRAINT_NAME CASCADE';
l_sql :='INSERT INTO TMP_CONSTRAINT (TABLE_NAME,CONSTRAINT_NAME)
VALUES ('':TABLE_NAME'', '':CONSTRAINT_NAME'')';
EXECUTE IMMEDIATE l_sql USING k.TABLE_NAME, k.CONSTRAINT_NAME;
END LOOP;
Above dynamic SQL to take the variable from a cursor and disable constraint accordingly and insert record to a temp table. I am getting error "bind variable does not exist" in the update statement.

It is actually caused by the single code in INSERT
Corrected as per following:
l_sql :='INSERT INTO TMP_ENABLED_CONSTRAINT (TABLE_NAME,CONSTRAINT_NAME) VALUES (:TABLE_NAME ,:CONSTRAINT_NAME)';

Related

dynamically change column in oracle cursor

I have 50 columns in one table and need to update each column.
Trying the below plsql code. (commented update section is working).
But dynamically generated column is not accepting.
(PL/SQL: ORA-01747: invalid user.table.column, table.column, or column specification)
Anybody can help please?
DECLARE
cursor udas is
select 5109 as udaid from dual
union all
select 8209 as udaid from dual;
BEGIN
for uda in udas loop
DECLARE
cursor c1 is
select
x.item, x.uda_id, x.uda_value, x.uda_value_desc
from
hp2_uda_data x
where
x.uda_type='LOV'
and x.uda_id=uda.udaid;
begin
for i in c1 loop
begin
/*update testtable set item_uda_5109_v=i.uda_value,
item_uda_5109_d=i.uda_value_desc where item_code=i.item;*/
update testtable set 'item_uda_'||uda.udaid||'_v'=i.uda_value,
'item_uda_'||uda.udaid||'_d'=i.uda_value_desc where item_code=i.item;
end;
end loop;
commit;
end;
end loop;
END;
Dynamic code requires execute immediate:
execute immediate
'update testtable
set item_uda_'||uda.udaid||'_v = :b1
, item_uda_'||uda.udaid||'_d = :b2
where item_code = :b3'
using i.uda_value, i.uda_value_desc, i.item;
It can be useful to construct the dynamic code in a variable so that you can report or log it in the event of failure.
I also recommend looking into code indentation as a useful technique for making code readable.

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.

How to use a bind variable in trigger body?

I'm new to PL/SQL. I'm using oracle 11g XE along with sql developer. I'm trying to create to create an after insert trigger as follows
create or replace trigger tr1
after
insert ON
employee
for each row
begin
print :new.emp_id;
end;
The employee table is as follows
create table employee
( emp_id varchar2(5) primary key,
emp_name varchar2(10),
salary number,
company varchar2(10) foreign key references companies(comp_name)
);
When I run the statement I got a 'enter binds' window for the bind variable :new. But I was confused that why do I need to enter the value for :new since it is pseudorecord. Then I entered 'employee' as the values for :new. Now I'm getting the following error.
Error(2,8): PLS-00103: Encountered the symbol "" when expecting one of the following: := . ( # % ; The symbol ":=" was substituted for "" to continue.
Your problem is not in the :new pseudorecord. The error is coming from the usage of print, which is used to print the bind variable used in successful PL/SQL block or used in an EXECUTE command. For example, you can use it this way:
VARIABLE n NUMBER
BEGIN
:n := 1;
END;
/
Then
PRINT n;
But if you want to test the value being inserted, you can use DBMS_OUTPUT.PUT_LINE like this:
create or replace trigger tr1
after
insert ON
employee
for each row
BEGIN
dbms_output.put_line(:new.emp_id);
END;
/
Enable DBMS_OUTPUT window in your SQL Developer, then run
insert into employee values(1, 'empName', 1000, 'ABC');
You'll see 1 printed out.
However, you can always test the value from the table. Because the value should be already inserted into table. You can just query.

PL/SQL Execute immediate create table and insert data into it

Let's have a look on my source code:
CREATE OR REPLACE PROCEDURE MAKE_COPY_OF_CLASSROOMS AUTHID CURRENT_USER AS
TYPE classrooms_table_type IS TABLE OF classrooms%ROWTYPE INDEX BY PLS_INTEGER;
classrooms_backup classrooms_table_type;
CURSOR classrooms_cursor IS
SELECT *
FROM classrooms
WHERE year = 1
ORDER BY name;
v_rowcnt PLS_INTEGER := 0;
BEGIN
OPEN classrooms_cursor;
FETCH classrooms_cursor
BULK COLLECT INTO classrooms_backup;
CLOSE classrooms_cursor;
EXECUTE IMMEDIATE 'CREATE TABLE classrooms_copy AS (SELECT * FROM classrooms WHERE 1 = 2)';
--COPY ALL STORED DATA FROM classrooms_backup TO classrooms_copy
END MAKE_COPY_OF_classrooms;
I'm stucked for hours on trying to insert data from "classrooms_backup" into the table "classrooms_copy", which is created by EXECUTE IMMEDIATE command. It's necessary to create table "classrooms_copy" via EXECUTE IMMEDIATE command. I tried to create another EXECUTE command with for loop in it:
EXECUTE IMMEDIATE 'FOR i IN classrooms_backup.FIRST..classrooms_backup.LAST LOOP
INSERT INTO classrooms_copy(id,room_id,year,name)
VALUES(classrooms_backup(i).id,classrooms_backup(i).room_id,classrooms_backup(i).year,classrooms_backup(i).name);
END LOOP;';
But it's road to the hell. I'm retrieving an invalid SQL statement error.
Thanks for your help!
There's no need for much PL/SQL here. Also, try to avoid the keyword CURSOR - there's almost always a better way to do it.
create or replace procedure make_copy_of_classrooms authid current_user as
begin
execute immediate '
create table classrooms_copy as
select *
from classrooms
where year = 1
order by name
';
end make_copy_of_classrooms;
/

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