Update using the table list - oracle

I am facing an issue while updating 100 tables. Problem is as below:
I have to update 299 columns in 100 tables and for that I have to create one oracle procedure. I have created a table with two columns where I am storing the table name and the columns for e.g.:
lookup_table:------
table_name column_name
Now what I want to do is pick every row and update the cols based on table name, hence I need to use the table_name and column_name as variables.
Let me know if anyone worked on this type of scenario.

For such dynamic operations, you need to (ab)use EXECUTE IMMEDIATE in PL/SQL. In SQL, you cannot use object names dynamically, it must be static.
I would suggest to do it in SQL and prepare the required update statements. Using a good text editor it shouldn't be a difficult task.
But, if you still want to do it in PL/SQL, then you need to first build the sql statements dynamically and then use EXECUTE IMMEDIATE.
For example,
SQL> set serveroutput on
SQL> DECLARE
2 var_sql VARCHAR2(1000);
3 var_tab VARCHAR2(10);
4 var_ename VARCHAR2(10);
5 BEGIN
6 var_tab:= 'EMP';
7 var_sql :='SELECT empno FROM '||var_tab||' WHERE empno=7369';
8 EXECUTE IMMEDIATE var_sql INTO var_ename;
9 DBMS_OUTPUT.PUT_LINE('Employee name is '||var_ename);
10 END;
11 /
Employee name is 7369
PL/SQL procedure successfully completed.
SQL>

Related

Oracle SELECT <var name> AS <column name> equivalent after stored procedure where <var name> is an outbound parameter (JDBC/SQL Only no SQL*Plus)

Does Oracle have a way other than using using DBMS_OUTPUT to render the content of returned variables coming back out of a stored procedure via SELECT?
I'm aware of functions too, but I don't have a say in rewriting things, in case that's what people are thinking of responding with.
DECLARE
NAME TIDAL.JOBMST.JOBMST_NAME%TYPE; -- Oracle syntax to base the type of variable upon a column in a table. It resolves to varchar2(256)
BEGIN
TIDAL.GETJOBNAMEFORID(1,NAME); -- 'NAME' is an outbound parameter of stored procedure and gets bound to variable 'NAME' in DECLARE above.
DBMS_OUTPUT.PUT_LINE('Name: ' || NAME); -- || is Oracle string concat `+` anywhere else!
END;
The program that processes this SQL via JDBC needs to be able to render output as a CSV, XML or raw payload. It can only do all these options with the "select" style output. (probably using Java's Resultset API)
The DBMS_OUTPUT.PUTLINE doesn't generate output within the program that processes the SQL. DBeaver does. So this doesn't work for me either.
I thought there would be some awkward SELECT :NAME FROM DUAL or SELECT NAME: = NAME INTO DUAL syntax I could use to render it, since Oracle won't allow a SELECT without a FROM akin to SQL Server (see below), but the solution eludes me.
In this case the result is a scalar, but it could equally be one or more records, or rows of a single column..
I would like to use AS in order to be able to label the column(s) for a downstream processes too.
Can someone tell me if this is possible?
The code has to pass JDBC SQL parser syntax checks and generates no ORA error code. The bulk of the solutions I see on Oracle on the internet seem flaky. SQL*Plus answers with things like var or exec or print don't seem to work with JDBC SQL. I've been trying to validate things via DBeaver too - and most of the time a colon prepends variable names it seems to prompt for input so I'm not sure if that/my Oracle knowledge, is muddying the waters and I should try SQL Developer to validate code instead.
This would be the equivalent in SQL Server of what I want to achieve in Oracle:
DECLARE
#NAME varchar(256),
EXEC GETJOBNAMEFORID
1
#NAME = #NAME OUTPUT;
SELECT #NAME As Name
Other that this canned example I don't have visibility to the stored procedures to know if a sys_refcursor is in use on outbound parameters either.
Is it possible? Kind of. This is SQL*Plus (command-line tool):
Procedure with an OUT parameter (just like yours):
SQL> create or replace procedure p_test (par_deptno in dept.deptno%type,
2 par_dname out dept.dname%type)
3 as
4 begin
5 select dname
6 into par_dname
7 from dept
8 where deptno = par_Deptno;
9 end;
10 /
Procedure created.
Declare a variable:
SQL> var v_dname varchar2(20);
Execute the procedure:
SQL> exec p_test(10, :v_dname);
PL/SQL procedure successfully completed.
Print the result:
SQL> print v_dname
V_DNAME
--------------------------------------------------------------------------------
ACCOUNTING
SQL>
What if the procedure returns many rows? Then you could return refcursor:
SQL> create or replace procedure p_test (par_deptno in dept.deptno%type,
2 par_dname out sys_refcursor)
3 as
4 begin
5 open par_dname for
6 select dname
7 from dept
8 where deptno <= par_deptno;
9 end;
10 /
Procedure created.
SQL> var v_dname refcursor
SQL>
SQL> exec p_test(40, :v_dname);
PL/SQL procedure successfully completed.
SQL> print v_dname
DNAME
--------------
ACCOUNTING
RESEARCH
SALES
OPERATIONS
SQL>

How to show stored trigger in sql?

I was working on a trigger, now I want to make some changes and see the code, is it possible to see, if so then how? the trigger is working fine, is there any command in plsql to where I can check out the code? I am using sql command line
user_triggers (or all_triggers) have the trigger source code. Similarly user_source (or all_source) have other source code.
General rule though that I follow is to always always always have a file structure where I keep the source. 100% rule that no one in the team is allowed to violate ever. Then I view the act of creating trigger equivalent to "compiling" in traditional programming. In that model, you would have a directory tree for example
<project>/src
<project>/src/plsql
<project>/src/plsql/<folder for each package>/<files>
<project>/src/plsql/<folder for each table>/<triggers>
And then "modifying" is simply changing them here and "compiling" again (compiling will imply running these via sqlplus - or still better creating a shell script.
In this model, you can easily incorporate several available version control tools as well.
GUI would display it prettier, but SQL*Plus can do it as well. Here's an example:
Creating a sample trigger:
SQL> create or replace trigger trg_update_percentage
2 after update or insert on item
3 for each row
4 begin
5 insert into students_percentage (sid, total_per)
6 select sid, total from student_report
7 where sid = :new.sid;
8 end;
9 /
Trigger created.
Fetch its description from USER_TRIGGERS; as the body is stored into the LONG datatype column, set long should be used (otherwise you won't see the complete code).
SQL> set long 4000
SQL> select trigger_name, trigger_type, triggering_event, table_name, trigger_body
2 from user_Triggers where trigger_name = upper('trg_update_percentage');
TRIGGER_NAME TRIGGER_TYPE TRIGGERING_EVENT TABLE_NAME
------------------------- -------------------- -------------------- ----------
TRIGGER_BODY
--------------------------------------------------------------------------------
TRG_UPDATE_PERCENTAGE AFTER EACH ROW INSERT OR UPDATE ITEM
begin
insert into students_percentage (sid, total_per)
select sid, total from student_report
where sid = :new.sid;
end;
SQL>

Oracle configuration. "create or replace" function create invalid object

I recently moved my database to a new server (both Oracle 11g).
In the new host, there is a weird behavior, that whenever I run something like:
create or replace test_trigger
before insert or update
on test_table
for each row
begin
select 1 from dual;
end;
/
The trigger created is invalid without any error in log. I tried to recompile, it still invalid.
It only happen with the function "create or replace". If I drop the trigger and re-create again, it would be valid.
My question is, did I config something incorrectly? How can I check it? Thank you.
Code you posted won't compile, not in any Oracle database I know. Why? Wrong syntax.
Here's a demonstration:
SQL> create or replace test_trigger
2 before insert or update
3 on test_table
4 for each row
5 begin
6 select 1 from dual;
create or replace test_trigger
*
ERROR at line 1:
ORA-00922: missing or invalid option
SQL> end;
SP2-0042: unknown command "end" - rest of line ignored.
SQL> /
So, what's wrong with it?
create (or replace) wants to know what you're going to create. "test_trigger"? As far as Oracle is concerned, that could be "mickey_mouse" and the result will be the same. It is the trigger keyword that is missing
SELECT in PL/SQL requires an INTO clause, so that you could store the result into something
in order to be able to do that, you have to declare a variable
Here's code that, actually, compiles:
SQL> create or replace trigger test_trigger --> this
2 before insert or update
3 on test_table
4 for each row
5 declare
6 l_dummy number; --> this
7 begin
8 select 1
9 into l_dummy --> this
10 from dual;
11 end;
12 /
Trigger created.
SQL>
So, it seems that you misinterpret reality.

Dropping multiple columns: PLSQL and user_tab_cols

I have a table TABLE_X and it has multiple columns beginning with M_ characters which needs to be dropped. I decided to use the following PLSQL code to drop almost 100 columns beginning with M_ characters. Is it a good employment of dynamic sql and cursors? Can it be better? I didn't know more simple way since ALTER TABLE ... DROP COLUMN doesn't allow subquery to specify multiple column names.
declare
rcur sys_refcursor;
cn user_tab_cols.column_name%type;
begin
open rcur for select column_name from user_tab_cols where table_name='TABLE_X' and column_name LIKE 'M_%';
loop
fetch rcur into cn;
exit when rcur%NOTFOUND;
execute immediate 'alter table TABLE_X drop column '||cn;--works great
execute immediate 'alter table TABLE_X drop column :col'using cn;--error
end loop;
close rcur;
end;
Also. Why is it impossible to use 'using cn'?
This is a reasonable use of dynamic SQL. I would seriously question an underlying data model that has hundreds of columns in a single table that start with the same prefix and all need to be dropped. That implies to me that the data model itself is likely to be highly problematic.
Even using dynamic SQL, you cannot use bind variables for column names, table names, schema names, etc. Oracle needs to know at parse time what objects and columns are involved in a SQL statement. Since bind variables are supplied after the parse phase, however, you cannot specify a bind variable that changes what objects and/or columns a SQL statement is affecting.
The syntax for dropping multiple columns in a single alter statement is this:
SQL> desc t42
Name Null? Type
----------------------------------------- -------- ----------------------
COL1 NUMBER
COL2 DATE
COL3 VARCHAR2(30)
COL4 NUMBER
SQL> alter table t42 drop (col2, col3)
2 /
Table altered.
SQL> desc t42
Name Null? Type
----------------------------------------- -------- ----------------------
COL1 NUMBER
COL4 NUMBER
SQL>
So, if you really need to optimize the operation, you'll need to build up the statement incrementally - or use a string aggregation technique.
However, I would question whether you ought to be running a statement like this often enough to need to optimize it.

Can't create trigger using SQLPlus in Oracle

I'm Learning Oracle and wanted to try creating a trigger. I tried this example form a book in sqlplus.
SQL> CREATE OR REPLACE TRIGGER policy_bull BEFORE insert or update
2 ON emp
3 FOR EACH ROW
4 BEGIN
5 :new.salary := 200;
6 END
7 /
ERROR at line 1:
ORA-04089: cannot create triggers on objects owned by SYS
even though I logged in as SYS using
sqlplus "sys/oracle as sysdba"
You need to type / on a blank line to tell SQLPLUS to run the statement.
Oracle forbids creating triggers on objects owned by SYS.
Did you create the table emp as SYS? You probably want to be a regular user to do that. emp doesn't sound like a system table.
I think a semi-colon is missing after END.
Also mention SYS.emp
SQL> CREATE OR REPLACE TRIGGER policy_bull BEFORE insert or update
2 of SALARY on EMP
3 FOR EACH ROW
4 BEGIN
5 :new.salary := 200;
6 END
7 /
you have to type the column where the "NEW SALARY" is ppl its SALARY so ...or update of SALARY on EMP...

Resources