oracle procedure ORA-00942 - oracle

I'm trying to execute a Merge procedure Iv'e created but I encounter the following error:
Could not get schema Object:java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist
I read in forum about the error and I made sure I'm on the right scheme.
In addition, the merge query works properly.
any suggestion?
procedure
create or replace procedure insert_or_update_Account
IS
BEGIN
MERGE INTO CRMAS_ODS_RAW_DATA.ACCOUNT T
USING CRMAS_ODS_RAW_DATA.ACCOUNT_TMP S
ON ( T.TCCID=S.TCCID)
WHEN MATCHED THEN
UPDATE
SET
T.BATCH_ID =S.BATCH_ID ,
T.SOURCE_SYSTEM =S.SOURCE_SYSTEM ,
T.UPDATE_DATE =S.UPDATE_DATE ,
T.MLI_LOCALID =S.MLI_LOCALID
WHERE
T.BATCH_ID <>S.BATCH_ID OR
T.SOURCE_SYSTEM <>S.SOURCE_SYSTEM OR
T.MLI_LOCALID <>S.MLI_LOCALID
WHEN NOT MATCHED THEN
INSERT (T.BATCH_ID,T.SOURCE_SYSTEM,T.UPDATE_DATE,T.TCCID,T.MLI_LOCALID,T.MLI_LOCALSYSTEMNAME)
VALUES (S.BATCH_ID,S.SOURCE_SYSTEM,S.UPDATE_DATE,S.TCCID,S.MLI_LOCALID,S.MLI_LOCALSYSTEMNAME);
commit;
END insert_or_update_Account;

The procedure owner should be granted privileges on CRMAS_ODS_RAW_DATA.ACCOUNT table directly, not via role.
The fact that MERGE works in SQL (but not in PL/SQL) sounds exactly like that.

Related

Oracle - DBA_SCHEDULER_JOB_RUN_DETAILS get's different results (owners) from script and procedure

on one of my servers i detect weird behaviour:
I have table TEST_OWNERS(owner varchar2(100)
When I execute this statement:
INSERT INTO TEST_OWNERS
select distinct owner from DBA_SCHEDULER_JOB_RUN_DETAILS;
commit;
I have all owners in the table.
But, when I try to create procedure with the same statement:
CREATE OR REPLACE PROCEDURE TEST_OWNERS_P IS
BEGIN
EXECUTE IMMEDIATE('TRUNCATE TABLE TEST_OWNERS');
INSERT INTO TEST_OWNERS
select distinct owner from DBA_SCHEDULER_JOB_RUN_DETAILS;
commit;
END;
And execute it from the same window, the same session - I can see only user, who executed procedure :|
On another server evyrything is ok - script and procedure returns the same results.
What can be wrong?
The query that you are using to populate the table is dependent on the jobs that have been run in the database. If there are different jobs running in DB1 than in DB2, then your query will likely have different results.
If you are just trying to get a list of users in the database, then you can use select username from dba_users

How to call Oracle stored procedure from azure data factory v2

My requirement is copy data from Oracle to SQL Server. Before copying from Oracle database, I need to update the Oracle table using procedure which has some logic.
How do I execute Oracle stored procedure from Azure datafactory?
I referred to this thread
if I use EXECUTE PROC_NAME (PARAM); in preCopy script it's failing with following error
Failure happened on 'Source' side.
ErrorCode=UserErrorOdbcOperationFailed,
Type=Microsoft.DataTransfer.Common.Shared.HybridDeliveryException
Message=ERROR [42000] [Microsoft][ODBC Oracle Wire Protocol driver]
[Oracle]ORA-00900: invalid SQL statement
Source=Microsoft.DataTransfer.ClientLibrary.Odbc.OdbcConnector,
Type=System.Data.Odbc.OdbcException
Message=ERROR [42000] [Microsoft][ODBC Oracle Wire Protocol driver]
[Oracle]ORA-00900: invalid SQL statement,Source=msora28.dll
Could anyone help on this?
Note: I am using self-hosted runtime environment for data factory
thanks!!
I used a Lookup Activity and a SELECT statement of DUAL TABLE. Due to the stored procedures can not be call from a statement SELECT. I created an oracle function and the function calls the stored procedure. The function returns a value and this value is received by the lookup activity.
When you define the function, you have to add the statement PRAGMA AUTONOMOUS_TRANSACTION. This is because Oracle does not allow to execute DML instructions with a SELECT statement by default. Then, you need to define that DML instructions in the Stored Procedure will be an autonomous transaction.
--Tabla
CREATE TABLE empleados(
emp_id NUMBER(9),
nombre VARCHAR2(100),
CONSTRAINT empleados_pk PRIMARY KEY(emp_id),
);
create or replace procedure insert_empleado (numero in NUMBER, nombre in VARCHAR2) is
begin
INSERT INTO empleados (emp_id, nombre)
Values(numero, nombre);
COMMIT;
end;
create or replace function funcinsert_empleado (numero in NUMBER, nombre in VARCHAR2)
return VARCHAR2
is
PRAGMA AUTONOMOUS_TRANSACTION;
begin
insert_empleado (numero, nombre);
return 'done';
end;
--statement in query of lookup
SELECT funcinsert_empleado ('1', 'Roger Federer')
FROM DUAL;
Example lookup
This is example in Spanish. https://dev.to/maritzag/ejecutar-un-stored-procedure-de-oracle-desde-data-factory-2jcp
In Oracle, EXECUTE X(Y) is a SQL*Plus-specific command shortcut for the PL/SQL statement BEGIN X(Y); END;. Since you are not using SQL*Plus, try the BEGIN/END syntax.
In case you only want to execute the DML query using the Azure Data Factory without procedure on oracle database :-
I have another solution where you can use the copy activity with the pre-copy feature of sink in-spite of lookup activity.
For this approach just follow the below steps :-
Keep both the source table and sink table as same ( Let say table A ) using the same linked service.
In sink use the pre-copy script feature and keep the DML (Insert/Update/Delete ) query that you want to perform over the table B.( This table is not necessary to be same as table A )
In case you want to avoid the copy of data to same table you can select query option in the source part and provide a where clause which is not going to satisfy and hence no copy of data will happen .
or you can create a table temp with one column and one row .
I have tested both the options and it works ... good part of above solution is you can avoid the procedure or function creation and maintenance .

I am facing an issue with deletion operation in Stored procedures(packages)

I am facing an issue here. I have a table Products where there are columns called prod_trkg_tran_id and cntr_nbr etc. I also have two tables instance1 and instance2 which also contains prod_trkg_tran_id and cntr_nbr and they have one row of data each with same cntr_nbr. I ran a query like below in Oracle SQLDeveloper. It worked fine and deleted a row from prod_trkg_tran. Can you explain this??
But when i tried this in SP by assigning:
p_where_clause:= 'WHERE t.prod_trkg_tran_id in (
select distinct tp82.PROD_TRKG_TAN_ID
from instance_1 tp21
join instance_2 tp82 on tp21.cntr_nbr=tp82.cntr_nbr
)'
and called a method delete_table which a statement contains
'DELETE FROM ' || p_table_name ||' t ' || p_where_clause;
p_table_name is prod_trkg_tran and p_where_clause is the one which I defined earlier.
If I run this, SP records are not getting deleted from prod_trkg_tran.
Ideally it was supposed to delete like I tried in SQLDeveloper. Can you explain this?
delete from prod_trkg_tran t
WHERE t.prod_trkg_tran_id in (
select distinct tp82.PROD_TRKG_TRAN_ID
from instance_1 tp21
join instance_2 tp82 on tp21.cntr_nbr=tp82.cntr_nbr
);
It is most probably a grant issue where executing schema/user does not have grant for delete or select aforamentioned tables.
If your user have DBA privileges you do not encounter with this error while using SQL Developer, however Stored Procedure does.
In your case, your tables may be synonyms to another schema table and you may not have grants on these tables.
Please make sure that you have sufficient grants.
By the way, what is the error that you are facing?

truncate and insert within procedure don't work together

I need to do truncate table and then insert data in that table using procedure.
However, one does like dinamic sql but the other one doesn't:
create or replace
procedure RECREATE_AGGREGATE
AUTHID DEFINER
AS
BEGIN
TRUNCATE TABLE AGGREGATE;
INSERT INTO AGGREGATE SELECT * FROM OLD_AGGREGATE;
END;
Error(6,14): PLS-00103: Encountered the symbol "TABLE" when expecting one of the following: := . ( # % ; The symbol ":= was inserted before "TABLE" to continue.
If I add execute immediate around TRUNCATE statement, it works fine, but insert is erroring out.
If I remove it, TRUNCATE TABLE complains...
create or replace
procedure RECREATE_AGGREGATE
AUTHID DEFINER
AS
BEGIN
execute immediate 'TRUNCATE TABLE AGGREGATE';
INSERT INTO AGGREGATE SELECT * FROM OLD_AGGREGATE;
END;
Error(7,5): PL/SQL: SQL Statement ignored
Error(7,84): PL/SQL: ORA-00942: table or view does not exist
Can some shed some light here?
create or replace
procedure RECREATE_AGGREGATE
AUTHID DEFINER
AS
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE AGGREGATE';
INSERT INTO AGGREGATE SELECT * FROM OLD_AGGREGATE;
END;
will work assuming that you have appropriate privileges.
Based on your edit (and echoing #OracleUser's comment), you're likely getting an error running your INSERT statement because old_aggregate is owned by another user and you only have SELECT privileges on that table via a role. If you want to do something in a definer's rights stored procedure, you'll need to have those privileges granted directly to you (or be using 12c which lets you grant privileges to blocks of code rather than to users).
Assuming you want to use a definer's rights stored procedure, you'd need the owner of old_aggregate (or the DBA) to
GRANT SELECT
ON old_user.old_aggregate
TO new_user;
You can verify that you only have the privilege via a role by disabling roles for the session. I'll wager that if you do
SQL> set role none;
SQL> SELECT * FROM old_aggregate
that you'll get an ORA-00942 error as well. This is a good way of simulating what privileges will be available to the user inside a definer's rights stored procedure.
"TRUNCATE is DDL (data definition language). You cannot perform DDL from within PL/SQL. "
http://www.orafaq.com/forum/t/119427

DDL statements in PL/SQL?

I am trying the code below to create a table in PL/SQL:
DECLARE
V_NAME VARCHAR2(20);
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE TEMP(NAME VARCHAR(20))';
EXECUTE IMMEDIATE 'INSERT INTO TEMP VALUES(''XYZ'')';
SELECT NAME INTO V_NAME FROM TEMP;
END;
/
The SELECT statement fails with this error:
PL/SQL: ORA-00942: table or view does not exist
Is it possible to CREATE, INSERT and SELECT all in a single PL/SQL Block one after other?
I assume you're doing something like the following:
declare
v_temp varchar2(20);
begin
execute immediate 'create table temp(name varchar(20))';
execute immediate 'insert into temp values(''XYZ'')';
select name into v_name from temp;
end;
At compile time the table, TEMP, does not exist. It hasn't been created yet. As it doesn't exist you can't select from it; you therefore also have to do the SELECT dynamically. There isn't actually any need to do a SELECT in this particular situation though you can use the returning into syntax.
declare
v_temp varchar2(20)
begin
execute immediate 'create table temp(name varchar2(20))';
execute immediate 'insert into temp
values(''XYZ'')
returning name into :1'
returning into v_temp;
end;
However, needing to dynamically create tables is normally an indication of a badly designed schema. It shouldn't really be necessary.
I can recommend René Nyffenegger's post "Why is dynamic SQL bad?" for reasons why you should avoid dynamic SQL, if at all possible, from a performance standpoint. Please also be aware that you are much more open to SQL injection and should use bind variables and DBMS_ASSERT to help guard against it.
If you run the program multiple time you will get an error even after modifying the program to run the select statement as dynamic SQL or using a returning into clause.
Because when you run the program first time it will create the table without any issue but when you run it next time as the table already created first time and you don't have a drop statement it will cause an error: "Table already exists in the Database".
So my suggestion is before creating a table in a pl/sql program always check if there is any table with the same name already exists in the database or not. You can do this check using a Data dictionary views /system tables which store the metadata depending on your database type.
For Example in Oracle you can use following views to decide if a tables needs to be created or not:
DBA_TABLES ,
ALL_TABLES,
USER_TABLES

Resources