I had to use temporally the enabling cascade to fix some problems in my DB.
I used this alter:
ALTER TABLE table
DISABLE PRIMARY KEY CASCADE;
And now I'd want to undo it and enable all the constraints again. Have I got to enable them one by one?
Yes, you have to re-enable the the dependent constraints one by one. There is no magic cascade option for the re-enabling of the constraint.
Here is a quote from Darl Kuhn's "Pro Oracle Database 12c Administration" book. The information applies to Oracle 11g as well:
Keep in mind that there is no ENABLE ... CASCADE statement. To reenable the constraints, you have to query the data dictionary to determine which constraints have been disabled and then reenable them individually.
In line with that quote, przemo_pl has provided you a good answer to minimize the pain of handling your use case.
I don't know any way of automatic enabling constraints in a cascade way, even tried to google that but no results of any value.
So this is what I would do:
Go and ask dba_constraints for all constraints referencing this primary key:
select *
from dba_constraints
connect by prior constraint_name = r_constraint_name
start with constraint_name = '<your_primary_key_constraint>';
Just double check that those are the ones you should enable and create a script to enable them all:
select 'alter table ' || table_name || ' enable ' || constraint_name || ';'
from dba_constraints
connect by prior constraint_name = r_constraint_name
start with constraint_name = '<your_primary_key_constraint>'
where c.status = 'DISABLED';
and just run it...
Related
Since Oracle does not support disabling normal indexes, I would like to programatically drop all indexes on a table before a bulk update and recreate them once the update is complete. I imagine this would require some custom PL/SQL. Can anyone offer a solution to this? Maybe someone here has already written such a script.
For reference, here is a solution for SQL Server: Automatically Drop and Recreate current indexes.
set head off
set echo off
set pages 1000
set lines 300
set feedback off
spool index_unusable.sql
select 'alter index ' || index_name || ' unusable;' from user_indexes where table_name='MY_TABLE';
spool off
#index_unusable.sql
do you bulk import setting this in your session before:
alter session set skip_unusable_indexes=true;
after the import:
set head off
set echo off
set pages 1000
set lines 300
set feedback off
spool index_rebuild.sql
select 'alter index ' || index_name || ' rebuild;' from user_indexes where table_name='MY_TABLE';
spool off
#index_rebuild.sql
If you have constraints you will need to disable them as well using:
alter table mytable modify constraint constraint_name DISABLE keep index;
I want to get all the canstraint_name so i could generate there ddl in java:
for each canstraint_name i'm going to execute :
DBMS_METADATA.SET_TRANSFORM_PARAM(DBMS_METADATA.SESSION_TRANSFORM,'CONSTRAINTS',true);
DBMS_METADATA.GET_DDL('CONSTRAINT','Constraint_name','hr');
I tried to execute this statement :
selectSQL = "SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE OWNER='" +Schemas+ "'";
I get a long list of constraints including invalid ones like: pdpzZlEqTgUxb7qMBM8w==$0
It generates an error when executing :
DBMS_METADATA.GET_DDL('CONSTRAINT','pdpzZlEqTgUxb7qMBM8w==$0','hr')
can't find pdpzZlEqTgUxb7qMBM8w==$0 in Schemas='hr' (the error it's in French)
The error message from GET_DDL suggest that those constraints belong to dropped tables (although those names start with BIN$). You cannot retrieve the DDL for those. If you don't want them you can do a
purge recyclebin;
before retrieving the constraints from user_constraints.
Or exclude them when retrieving the list of constraints:
SELECT constraint_name
FROM user_constraints
WHERE constraint_name NOT LIKE 'BIN$%';
This query:
SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE OWNER='" +Schemas+ "'";
doesn't really make sense. USER_CONSTRAINTS will only list constraints owned by the current user. You will never get constraints from a different schema when using USER_CONSTRAINTS.
If you want to get constraints from a different schema, you need to use ALL_CONSTRAINTS.
If you do want the current user's constraints, you can safely remove the WHERE clause.
How does Oracle use COLUMN_ID as found in USER_TAB_COLUMNS view? I just need to confirm that it does not use this internal column ordering while creating implicit indexes - such as when a primary key is enforced or a unique key constraint is created (that is key/constraints columns provided are used in the same order - left to right and not these internal column ordering). (if possible please point me in the direction of Oracle documentation.). Thanks in advance.
It'll be hard to find something stating that it doesn't do something, but there isn't anything stating that it will use column_id to override the index creation.
You can see all the reference to column_id in the documentation here; the only one that seems matter is the all_tab_columns view.
You can verify the order of the columns as used in the index by querying the all_ind_columns view, where you will be able to see that there is no enforced relationship between its column_position - which comes from the order the columns are listed in the index creation command - and column_id.
If you are specifically interested in checking indexes that back up constraints, you can do something like:
select ac.owner, ac.table_name, ac.constraint_name, ac.index_owner,
ac.index_name, aic.column_position, aic.column_name
from all_constraints ac
join all_ind_columns aic on aic.index_owner = coalesce(ac.index_owner, ac.owner)
and aic.index_name = ac.index_name
order by 1, 2, 3, 6;
... adding filters for owner or table as needed.
In our application, only about 25% of the database triggers show up in DBA_SOURCE. I know I can force the others to show up if I make an actual modification (like adding and removing a space) and then recompile the trigger, but I've got about 400 triggers to modify (it's rather a big application). Just recompiling the triggers with alter trigger <triggername> compile; didn't accomplish anything.
Without the triggers being in DBA_SOURCE, we can't do text searches on the trigger code.
Is there some simpler way to accomplish this? And is there some way to prevent the problem in the future?
We're on Oracle 10.2.0.5.0.
I believe you can find the source in all_triggers. Unfortunately, the data is in a LONG variable (Oracle example of do as I say, not as I do). So, the easiest thing would be to create a scratch table to use, populate it with the data converted to CLOB, and then search:
CREATE TABLE tr (trigger_name VARCHAR2(32), trigger_body CLOB);
INSERT INTO tr
(SELECT trigger_name, TO_LOB(trigger_body)
FROM all_triggers
WHERE owner = 'xxx');
SELECT trigger_name
FROM tr
WHERE trigger_body LIKE '%something%';
I'm not sure why the dba_source view is only sparsely populated for triggers. It's that way on my 10.2.0.4 database as well.
EDIT:
Here is a short script you can use to recreate all your triggers, at which point they should all be in dba_source:
CREATE TABLE temp_sql (sql1 CLOB, sql2 CLOB);
INSERT INTO temp_sql (sql1, sql2) (
SELECT 'CREATE OR REPLACE TRIGGER '||
DESCRIPTION||' '||CASE WHEN when_clause IS NULL THEN NULL ELSE 'WHEN('||when_clause||')' END sql1,
to_lob(trigger_body) sql2
FROM all_triggers
WHERE table_owner = 'theowner');
DECLARE
v_sql VARCHAR2(32760);
BEGIN
FOR R IN (SELECT sql1||' '||sql2 S FROM temp_sql) LOOP
v_sql := R.s;
EXECUTE IMMEDIATE v_sql;
END LOOP;
END;
/
We had the same issue. It's a migration issue from older versions of Oracle.
Triggers were not included in DBA_SOURCE in an earlier version (8?, 9i?) and did not get added to DBA_SOURCE when migrating to newer versions. A recompile did not put them into DBA_SOURCE. But if you drop and recreate the triggers, they will be included in DBA_SOURCE.
So my guess is you have some old triggers and have migrated the database in place to newer versions.
Who owns the triggers?
and, of course, you tried
select owner, object_name
from all_objects
where object_type = 'TRIGGER'
and owner in ('schema1','schema2')
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;
/