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

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?

Related

Oracle - using synonym as variable

i need to use synonym as variable in a block. I have 2 different schemas with same tables on them and job that switches between schemas making one active. Now I want to write a block checking which schema is active with ALL_SYNONYMS and using result as part of a query.
Here is example:
DECLARE
OWNER VARCHAR2(15);
BEGIN
SELECT TABLE_OWNER
INTO OWNER
FROM ALL_SYNONYMS
WHERE TABLE_NAME = 'MY_TABLE1';
SELECT *
FROM OWNER.MY_TABLE2 ;
END;
But I’m getting ORA-06550 table or view does not exist, and when i run query itself where i put value from ALL_SYNONYMS it returns result.
Any idea how to fix this?
Thanks
You are attempting using symptoms incorrectly. Synonyms are used so you do not need to know which is active. According to the documentation:
Synonyms provide both data independence and location transparency.
Synonyms permit applications to function without modification
regardless of which user owns the table or view and regardless of
which database holds the table or view.
You just use the synonym instead of the object itself.
create table evens( id integer generated always as identity
, val integer
) ;
create table odds( id integer generated always as identity
, val integer
) ;
insert all
when mod(val,2) = 0 then into evens(val)
when mod(val,2) = 1 then into odds(val)
select level val
from dual connect by level <= 10;
-- create the synonym then use it in Select;
create or replace synonym current_even_odd for evens;
select * from current_even_odd;
-- now change the synonym, then run the EXACT same query.
create or replace synonym current_even_odd for odds;
select * from current_even_odd;
In this case it is not quite without modification, you need to change the synonym, But it seems you are trying that already.
Note: You cannot create a synonym for a schema but must point it to a specific object.
I attempted a db<>fiddle for the above, but it appears it is having problems at the moment.
I agree with Belayer that the synonym should provide a layer of abstraction on your tables and your procedure shouldn't need to know what the schema is. But the "table or view does not exist" error is likely an issue related to privileges and definer's rights versus invoker's rights.
To directly reference an object in a procedure, the procedure's schema must have a direct grant to the table. However, an ad hoc query only needs a role with privileges on the object. This is why the SQL will work in your IDE but not in the procedure. Ensure the code that modifies objects and switches synonyms is granting privileges to both roles and directly to schemas.
If direct grants are not possible, you will need to modify the procedure to use AUTHID CURRENT_USER and change the SQL statements to use dynamic SQL - which can be a huge pain. For example:
create or replace procedure test_procedure authid current_user is
v_count number;
begin
execute immediate
q'[
select count(*)
from some_table
]'
into v_count;
end test_procedure;
/
If you really do need to manually switch between schemas, then you may want to consider using something like execute immediate 'alter session set current_schema=schema1'; in the procedure and using dynamic SQL for all of the querying.

oracle procedure ORA-00942

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.

sqldeveloper query other users

I have a database that has say 100 other_users.
I am logged in as the database owner and I want to query a specific table in all the other users schemas.
So let's say each schema has a table called propertyvalue.
I want to find out which schemas have this value set to TRUE.
Is there a way I can run a select statement against all the other users schemas without specifically pointing to an individual schema.
Something like:
select * from otherusers.propertyvalue where value = 'TRUE', which doesn't work as I have tried that.
Thanks.
You can write a statement that will write select statements to do this
SELECT 'SELECT '||owner||'.'||table_name||'.'||column_name ||
' FROM '||owner||'.'||table_name||';'
FROM All_Tab_Cols atc
WHERE atc.column_name = 'PROPERTYVALUE';
Run this statement as a user with select privilege on the table and then run the selects that are the output.
However tables with multiple rows will return all rows. Are you expecting that there is only one row in each table?
You could also write an anonymous block that will open a cursor with the same statement and output the results to a file/table/output.

How to update value of fields in a table found in every schema on an Oracle Server

I need to update the value of two fields in a table and in every schema containing that table on an Oracle Server (11g). I am from the SQL Server world, but recognize that the architecture is different with multiple schemas under a single instance, not multiple databases under a single instance. The reason for this update is to ensure that while database development and testing takes place on copies of client databases, the clients do not accidentally receive emails (according to settings defined in certain columns of a table in each schema/database).
I am using SQL Developer, but could also apply SQLplus instead. Assuming the Server name is "myServer", the tablename is "myTable" and the fields are "Field1" and "Field2" of this table, can somebody help in providing some SQL that will perform a global update of all schemas on myServer setting Field1 = 'N' and Field2 = NULL in myTable? Or direct me to a link that does answer this question? I first ran multiple searches and found nothing.
Thanks
You can use dynamic SQL
FOR tbl IN (SELECT owner, table_name
FROM dba_tables
WHERE table_name = 'MYTABLE')
LOOP
EXECUTE IMMEDIATE 'update ' || tbl.owner || '.' || tbl.table_name ||
' set field1 = ''N'', ' ||
' field2 = null ';
END LOOP;
You can add some additional logging and you probably want to build the SQL statement in a local variable so that you can log it if something goes wrong. This also assumes that you're running as a user that has access to dba_tables. You could use all_tables if you want to update every table with that name that you have access to (which might not cover every table in the database).

Oracle sample data problems

So, I have this java based data trasformation / masking tool, which I wanted to test out on Oracle 10g. The good part with Oracle 10g is that you get a load of sample schemas with half a million records in some. The schemas are : SH, OE, HR, IX and etc. So, I installed 10g, found out that the installation scripts are under ORACLE_HOME/demo/scripts.
I customized these scripts a bit to run in batch mode. That solves one half of my requirement - to create source data for my testing my data transformation software.
The second half of the requirement is that I create the same schemas under different names (TR_HR, TR_OE and so on...) without any data. These schemas would represent my target schemas. So, in short, my software would pick up data from a table in a schema and load it up in to the same table in a different schema.
Now, I have two issues in creating my target schema and emptying it.
I would like this in a batch job. But the oracle scripts you get, the sample schema names are not configurable. So, I tried creating a script, replacing OE with TR_OE, HR with TR_HR and so on. However, this approach is kind of irritating coz the sample schemas are kind of complicated in the way they are created; Oracle creates synonyms, views, materialized views, data types and lot of weird stuff.
I would like the target schemas (TR_HR, TR_OE,...) to be empty. But some of the schemas have circular references, which would not allow me to delete data. The only work around seems to be removing certain foreign keys, deleting data and then adding the constraints back.
Is there any easy way to all this, without all this fuss? I would need a complicated data set for my testing (complicated as in tables with triggers, multiple hierarchies.. for instance.. a child table that has children up to 5 levels, a parent table that refers to an IOT table and an IOT table that refers to a non-IOT table etc..). The sample schemas are just about perfect from a data set perspective. The only challenge I see is in automating this whole process of loading up the source schemas, and then creating the target schemas and emptying them. Appreciate your help and suggestions.
UPDATE
The main script that you are required to run for manually installing oracle sample schemas is mkplug.sql. Here is the line that loads the schemas up from a dmp file:
host imp "'sys/&&password_sys AS SYSDBA'" transport_tablespace=y file=&imp_file log=&imp_logfile datafiles='&datafile' tablespaces=EXAMPLE tts_owners=hr,oe,pm,ix,sh
Well, I tried modifying this line (after patching up path related issues on mkplug.sql and all other sql files) to this:
host imp "'sys/&&password_sys AS SYSDBA'" rows=n transport_tablespace=y file=&imp_file log=&imp_logfile datafiles='&datafile' tablespaces=EXAMPLE tts_owners=hr,oe,pm,ix,sh
And... it did NOT help. The schema got created with row data, despite rows=n attribute :(
Since you're already familiar with exp/imp (or expdp/impdp) from the Oracle scripts that use the .dmp file, why not just:
Create the empty TR_xxx schemas
Populate the TR_xxx schema from the
xxx .dmp file with the FROMUSER/TOUSER
options and ROWS=N (similar options
exist for expdp/impdp)
[Edit after reading your comment about the transportable tablespaces]
I didn't know that the Oracle scripts were using transportable tablespaces and that multiple schemas were being imported from a single file. This is probably the most straightforward way to create your new empty TR schemas:
Start with the standard, populated
database built with the Oracle
scripts
Create no-data export files on a
schema-by-schema basis (OE shown) by:
exp sys/&&password_sys AS SYSDBA
file=oe_nodata.dmp
log=oe_nodata_exp.log owner=OE rows=N
grants=N
(You should only have to do this once
and this dmp file can be reused)
Now, your script should:
Drop any TR_ users with the CASCADE
option
Re-create the TR_ users
Populate the schema objects (OE
shown) by:
host imp "'sys/&&password_sys AS
SYSDBA'" file=oe_nodata.dmp
log=tr_oe_imp.log fromuser=OE
touser=TR_OE
Here is an anonymos block which - for a given schema - disables triggers and foreign keys, truncates all the tables and then re-enables triggers and foreign keys. It uses truncate for speed but obviously this means no rollback: so be careful which schema name you supply! It's easy enough to convert that call into a delete from statement if you prefer.
The script is a fine example of cut'n'paste programming, and would no doubt benefit from some refactoring to remove the repetition.
begin
<< dis_triggers >>
for trgs in ( select owner, trigger_name
from all_triggers
where table_owner = '&&schema_name' )
loop
execute immediate 'alter trigger '||trgs.owner||'.'||trgs.trigger_name
||' disable';
end loop dis_triggers;
<< dis_fkeys >>
for fkeys in ( select owner, table_name, constraint_name
from all_constraints
where owner = '&&schema_name'
and constraint_type = 'R')
loop
execute immediate 'alter table '||fkeys.owner||'.'||fkeys.table_name
||' disable constraint '||fkeys.constraint_name;
end loop dis_fkeys;
<< zap_tables >>
for tabs in ( select owner, table_name
from all_tables
where owner = '&&schema_name' )
loop
execute immediate 'truncate table '||tabs.owner||'.'||tabs.table_name
||' reuse storage';
end loop zap_tables;
<< en_fkeys >>
for fkeys in ( select owner, table_name, constraint_name
from all_constraints
where owner = '&&schema_name'
and constraint_type = 'R')
loop
execute immediate 'alter table '||fkeys.owner||'.'||fkeys.table_name
||' enable constraint '||fkeys.constraint_name;
end loop en_fkeys;
<< en_triggers >>
for trgs in ( select owner, trigger_name
from all_triggers
where table_owner = '&&schema_name' )
loop
execute immediate 'alter trigger '||trgs.owner||'.'||trgs.trigger_name
||' enable';
end loop en_triggers;
end;
/

Resources