Guys my question is I don't know the constraint names that I've added to a table. But I need to remove or disable all those foreign key constraints. But how?
SQL> desc orders;
Name Null? Type
----------------------------------------- -------- ----------------------------
ORDER_ID NOT NULL VARCHAR2(10)
PRODUCT_ID VARCHAR2(10)
DATE_OF_ORDER TIMESTAMP(6)
CUST_ID VARCHAR2(10)
QUANTITY NUMBER(38)
TOTAL_PRICE FLOAT(10)
DELIVERY_STATUS VARCHAR2(10)
The related foreign constraints might be determined by using user_constraints dictionary view, and you can disable the foreign key constraint of this table by the following code block
BEGIN
FOR c IN
(
SELECT *
FROM user_constraints c
WHERE c.constraint_type = 'R'
AND c.table_name = 'ORDERS')
LOOP
EXECUTE IMMEDIATE 'ALTER TABLE '||c.table_name||
' DISABLE CONSTRAINT '||c.constraint_name;
END LOOP;
END;
/
If you're using a tool like sql developer you can just right click the table name in the navigator and select constraint > disable all or drop
Related
I was testing the following examples (1, 2 and 3) in APEX-Oracle SQL commands and all three examples seems to work fine, however, I thought the PRIMARY KEY is named/reserved keyword in oracle, so the question is there any difference between the primary keys in these three examples.
Please note that example_2 the primary key is in small letters
CREATE TABLE example_1(
ID int PRIMARY KEY,
LastName VARCHAR2(255) NOT NULL,
FirstName VARCHAR2(255),
Age int
);
CREATE TABLE example_2(
ID int primary key,
LastName VARCHAR2(255) NOT NULL,
FirstName VARCHAR2(255),
Age int
);
CREATE TABLE example_3(
ID int ,
LastName VARCHAR2(255) NOT NULL,
FirstName VARCHAR2(255),
Age int,
CONSTRAINT PK_example_3 PRIMARY KEY (ID)
);
No difference in functionality. Only difference is that for table example_3 the primary key is a named constraint and not a generated name.
"PRIMARY KEY" is not a reserved word (full list here) and case doesn't matter in the CREATE TABLE clause (object names can be case sensitive if enclosed in quotes)
You can easily check this yourself... query data dictionary USER_TABLES for details about the tables and USER_CONSTRAINTS to see if there are differences in the primary key constraints.
In Oracle INT is synonym for NUMBER(38) and that's bigger than a quad-precision integer. That's a big number that may be overkill for your app. I would recommend you use a smaller precision, like NUMBER(18) (a long) or so.
The first and second examples are equivalent. In the third case, you are assigning an explicit name (PK_EXAMPLE_3) to the primary key constraint. In the first two cases, the PK will end up with auto-generated "ugly" names. Not a big deal, but that name may be end up being different in different environments (dev, test, staging, prod) and that can be significant sometimes, when you submit SQL scripts to be executed by third parties, or in automated ways.
Other than that, your examples are almost equivalent.
As you noticed, letter case - in Oracle - doesn't matter. CREATE works as well as create or CrEAte. The same goes for primary key.
Letter case, though, would matter if you make a wrong step and decide to enclose names into double quotes; then you have to do that every time you reference that something (table, procedure, column, whatever), matching letter case exactly (but that's another issue we aren't discussing now).
You created table as
SQL> CREATE TABLE example_1(
2 ID int PRIMARY KEY,
3 LastName VARCHAR2(255) NOT NULL,
4 FirstName VARCHAR2(255),
5 Age int
6 );
Table created.
If you describe it, you'll notice that Oracle - by default - stores everything (into data dictionary) - in UPPER CASE and lets you reference it using any case you want:
SQL> desc example_1
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER(38)
LASTNAME NOT NULL VARCHAR2(255)
FIRSTNAME VARCHAR2(255)
AGE NUMBER(38)
SQL> select table_name from user_tables where table_name = 'EXAMPLE_1';
TABLE_NAME
--------------------
EXAMPLE_1
SQL> select id, LASTname, FirSTnaMe from exampLE_3;
no rows selected
SQL>
As you can see, your nicely written LastName became LASTNAME. As I said: you could have preserved it if you put it as "LastName" varchar2(255), but that's - in most cases - wrong and brings nothing but problems. Don't do that. Use e.g. last_name instead to improve readability.
As of constraints: as you didn't name them, Oracle set names automatically. These generic names aren't useful at all because you have no idea what they represent, simply by looking at their names:
SQL> select table_name, constraint_name, constraint_type
2 from user_constraints
3 where table_name = 'EXAMPLE_1';
TABLE_NAME CONSTRAINT_NAME CONSTRAINT_TYPE
-------------------- -------------------- --------------------
EXAMPLE_1 SYS_C009359 C
EXAMPLE_1 SYS_C009360 P
Yes, constraint type helps, but - why wouldn't you rather do as you did in your 3rd example and explicitly name the constraint?
SQL> select table_name, constraint_name, constraint_type
2 from user_constraints
3 where table_name = 'EXAMPLE_3';
TABLE_NAME CONSTRAINT_NAME CONSTRAINT_TYPE
-------------------- -------------------- --------------------
EXAMPLE_3 SYS_C009361 C
EXAMPLE_3 PK_EXAMPLE_3 P --> isn't this better?
SQL>
OK; you found two ways of creating (primary key) constraints:
one is inline (regardless of whether you give it a name or not):
id int primary key
another is out-of-line:
CONSTRAINT PK_example_3 PRIMARY KEY (ID)
the 3rd way is to use alter table statement:
SQL> CREATE TABLE example_2(
2 ID int,
3 LastName VARCHAR2(255) NOT NULL,
4 FirstName VARCHAR2(255),
5 Age int
6 );
Table created.
SQL> alter table example_2 add constraint pk_example_2 primary key (id);
Table altered.
I suggest you read carefully everything answerers said so far; you might find it useful.
I Was Working in an exercise and this question popup to my mind is there a specific function in pl/SQL can add a primary key constraint or any kind of constraints in an existing table?
Possible? Yes, with dynamic SQL.
SQL> create table test (id number);
Table created.
SQL> begin
2 execute immediate 'alter table test add constraint pk_test primary key (id)';
3 end;
4 /
PL/SQL procedure successfully completed.
SQL> select constraint_name from user_constraints
2 where table_name = 'TEST';
CONSTRAINT_NAME
------------------------------
PK_TEST
SQL>
I had to drop a table and remake it using an archive. In the process, I lost the table's constraints--things like the primary key--triggers, indices, and more. I have, however, the same table on a different DB, which has all the appropriate constraints.
I have tried adding the constraints, triggers, and indices manually, but there are just too many.
I was wondering if I could do something like:
alter table t73
modify col_n....col_n+1
using (select constraints from t73#otherdb)
No, that won't work.
What you could do is to use some GUI (like TOAD or SQL Developer), find table t73, have a look at its Script which contains all commands (CREATE TABLE, CREATE INDEX, CREATE CONSTRAINT, ...) and copy/paste the ones you need and execute them in your current database.
That would be quick.
If you want to do it right (you know, pretending you know what you're doing, just like I do), then see DBMS_METADATA.GET_DDL and extract those commands from the database.
The final result should be the same.
this is below example how you can use dbms_metadata.get_ddl oracle package
create table EX_EMPLOYEe ( id number(5) null, name varchar2(100))
/
alter table ex_Employee add constraint PK_EX_EMPLOYEE primary key (id)
/
alter table ex_Employee add constraint FK_EX_EMPLOYEE foreign key (id)
references ex_Employee1 (id)
/
create table EX_EMPLOYEe1 ( id number(5) null, name varchar2(100))
/
alter table ex_Employee1 add constraint PK_EX_EMPLOYEE1 primary key (id)
alter table SYS_PARAM_KEY_LABEL
add constraint FK1_SYS_PARAM_KEY_LABEL foreign key (KEY_GROUP_ID)
references SYS_PARAM_KEY_GROUP (KEY_GROUP_ID);
/
CREATE INDEX IDX_EX_EMPLOYEe on ex_employee(name)
/
Create or replace PROCEDURE P_EX_EMPLOYEe as
begin
select id from ex_employee where rownum=1;
end;
/
CREATE OR REPLACE TRIGGER TRG_EX_EMPLOYEe AFTER DELETE ON EX_EMPLOYEe
FOR EACH ROW
BEGIN
DELETE FROM ex_employee1 WHERE id = :OLD.ID;
END;
/
select to_char( dbms_metadata.get_ddl('CONSTRAINT', c.constraint_name)) from user_constraints c where table_name='EX_EMPLOYEE'
and c.constraint_type='P'
union
select to_char( dbms_metadata.get_ddl('REF_CONSTRAINT', c.constraint_name)) from user_constraints c where table_name='EX_EMPLOYEE'
and c.constraint_type='R'
union
select to_char( dbms_metadata.get_ddl('INDEX', c.index_name)) from user_indexes c where table_name='EX_EMPLOYEE'
union
select to_char( dbms_metadata.get_ddl('PROCEDURE', d.name)) from user_dependencies d where d.referenced_name='EX_EMPLOYEE'
and d.type='PROCEDURE'
union
select to_char( dbms_metadata.get_ddl('TRIGGER', d.name)) from user_dependencies d where d.referenced_name='EX_EMPLOYEE'
and d.type='TRIGGER'
I have looked over the internet and their solutions wont fix my problem, hence I'm asking for help here to check if there's mistakes in my coding.
I wanted to create a temporary table populated by other source tables and then implement it into the fact table. I have checked if the data type and the parameter is matching or the sequence of the keys but still it's giving me the error
"ORA-02291: integrity constraint (SYSTEM.SYS_C007167) violated -
parent key not found"
Fact Table:
CREATE TABLE DW_ITEMS7364 (
DW_ID int not null,
ManID char(5),
WHID char(5),
STKID char(5),
Profit number,
CONSTRAINT DW_ID PRIMARY KEY (DW_ID),
FOREIGN KEY(ManID) REFERENCES DW_MANUFACTURER7364,
FOREIGN KEY(WHID) REFERENCES DW_WAREHOUSE7364,
FOREIGN KEY(StkID) REFERENCES DW_STOCKITEM7364);
CREATE SEQUENCE seq_items7364 START WITH 101 increment by 1;
CREATE TRIGGER trg_items7364 BEFORE INSERT OR UPDATE ON DW_ITEMS7364
FOR EACH ROW
BEGIN
SELECT seq_items7364.NEXTVAL
INTO :new.DW_ID
FROM dual;
END;
Temporary Table:
CREATE TABLE TEMP_TAB7364 AS( SELECT m.ManID, w.WHID, s.STKID, (s.SellingPrice-s.PurchasePrice) AS "Profit"
FROM MANUFACTURER7364 m LEFT OUTER JOIN STOCKITEM7364 s ON s.ManID = m.ManID
RIGHT OUTER JOIN WAREHOUSE7364 w on s.WHID = w.WHID WHERE s.SELLINGPRICE IS NOT NULL AND s.PURCHASEPRICE IS NOT NULL
);
These are my source tables:
CREATE TABLE MANUFACTURER7364(
ManID char(5),
ManName varchar (25),
CityID char(5) NOT NULL,
PRIMARY KEY(ManID),
FOREIGN KEY(CityID) REFERENCES CITY7364);
CREATE TABLE WAREHOUSE7364(
WHID char(5),
MaxNoOfPallets number,
CostPerPallet number,
SecurityLevel char(1),
FreezerFacilities varchar(10),
QuarantineFacilities varchar(10),
CityID char(5) NOT NULL,
PRIMARY KEY(WHID),
FOREIGN KEY(CityID) REFERENCES CITY7364);
CREATE TABLE STOCKITEM7364(
StkID char(5),
StkName varchar(20),
SellingPrice number,
PurchasePrice number,
ManID char(5) NOT NULL,
WHID char(5) NOT NULL,
PRIMARY KEY(StkID),
FOREIGN KEY(ManID) REFERENCES MANUFACTURER7364,
FOREIGN KEY(WHID) REFERENCES WAREHOUSE7364);
As far as I can tell, nothing of what you posted raises that error.
Additional drawback is the way you chose to create foreign key constraints. If you don't name it, Oracle assigns the name itself and it looks the way you posted it: SYSTEM.SYS_C007167.
SQL> create table test
2 (id_dept number,
3 id_emp number,
4 foreign key (id_dept) references dept (deptno),
5 foreign key (id_emp) references emp (empno));
Table created.
SQL> select constraint_name from user_constraints where table_name = 'TEST';
CONSTRAINT_NAME
------------------------------
SYS_C008172
SYS_C008173
SQL>
When one of these fails, looking at its name you have no idea what went wrong, unless you investigate a little bit more:
SQL> select column_name from user_cons_columns where constraint_name = 'SYS_C008173';
COLUMN_NAME
-----------------------
ID_EMP
SQL>
But, if you name the constraint, it is way simpler:
SQL> create table test
2 (id_dept number,
3 id_emp number,
4 constraint fk_test_dept foreign key (id_dept) references dept (deptno),
5 constraint fk_test_emp foreign key (id_emp) references emp (empno));
Table created.
SQL> select constraint_name from user_constraints where table_name = 'TEST';
CONSTRAINT_NAME
------------------------------
FK_TEST_DEPT
FK_TEST_EMP
SQL>
Another major drawback one notices is what's written in front of the dot, here: SYSTEM.SYS_C007167. Yes, that would be SYSTEM. Shortly, don't do that. Leave SYS and SYSTEM alone; they are powerful, they are special. Why would you take the risk of destroying the database if you (un)intentionally do something hazardous? Create another user, grant required privileges and work in that schema.
If I understood you correctly, once you create that temp table (TEMP_TAB7364), its contents is transferred into the DW_ITEMS7364 and - doing so - you hit the error.
If that's so, what's the purpose of the temp table? Insert directly into the target table and save resources. Will it fail? Of course it will, unless you change the query. How? I don't know - make sure that you don't insert values that don't exist in any of three tables used for enforcing referential integrity.
Though, as you already have the temp table, if it isn't too large, a (relatively) quick & dirty way of finding out which row is responsible for the error can be found with a loop, such as
begin
for cur_r in (select col1, col2, ... from temp_table) loop
begin
insert into target (col1, col2, ...)
values (cur_r.col1, cur_r.col2, ...);
exception
when others then
dbms_output.put_line(sqlerrm ||': '|| cur_r.col1 ||', '||cur_r.col2);
end;
end loop;
end;
The inner BEGIN-END block is here to make sure that the PL/SQL code won't exit at the first error, but will display them all. Then review those values and find the reason that makes your query invalid.
Does Postgres have any way to say ALTER TABLE foo ADD CONSTRAINT bar ... which will just ignore the command if the constraint already exists, so that it doesn't raise an error?
A possible solution is to simply use DROP IF EXISTS before creating the new constraint.
ALTER TABLE foo DROP CONSTRAINT IF EXISTS bar;
ALTER TABLE foo ADD CONSTRAINT bar ...;
Seems easier than trying to query information_schema or catalogs, but might be slow on huge tables since it always recreates the constraint.
Edit 2015-07-13:
Kev pointed out in his answer that my solution creates a short window when the constraint doesn't exist and is not being enforced. While this is true, you can avoid such a window quite easily by wrapping both statements in a transaction.
This might help, although it may be a bit of a dirty hack:
create or replace function create_constraint_if_not_exists (
t_name text, c_name text, constraint_sql text
)
returns void AS
$$
begin
-- Look for our constraint
if not exists (select constraint_name
from information_schema.constraint_column_usage
where table_name = t_name and constraint_name = c_name) then
execute constraint_sql;
end if;
end;
$$ language 'plpgsql'
Then call with:
SELECT create_constraint_if_not_exists(
'foo',
'bar',
'ALTER TABLE foo ADD CONSTRAINT bar CHECK (foobies < 100);')
Updated:
As per Webmut's answer below suggesting:
ALTER TABLE foo DROP CONSTRAINT IF EXISTS bar;
ALTER TABLE foo ADD CONSTRAINT bar ...;
That's probably fine in your development database, or where you know you can shut out the apps that depend on this database for a maintenance window.
But if this is a lively mission critical 24x7 production environment you don't really want to be dropping constraints willy nilly like this. Even for a few milliseconds there's a short window where you're no longer enforcing your constraint which may allow errant values to slip through. That may have unintended consequences leading to considerable business costs at some point down the road.
You can use an exception handler inside an anonymous DO block to catch the duplicate object error.
DO $$
BEGIN
BEGIN
ALTER TABLE foo ADD CONSTRAINT bar ... ;
EXCEPTION
WHEN duplicate_table THEN -- postgres raises duplicate_table at surprising times. Ex.: for UNIQUE constraints.
WHEN duplicate_object THEN
RAISE NOTICE 'Table constraint foo.bar already exists';
END;
END $$;
http://www.postgresql.org/docs/9.4/static/sql-do.html http://www.postgresql.org/docs/9.4/static/plpgsql-control-structures.html
http://www.postgresql.org/docs/9.4/static/errcodes-appendix.html
you can run query over pg_constraint table to find constraint exists or not.like:
SELECT 1 FROM pg_constraint WHERE conname = 'constraint_name'"
Creating constraints can be an expensive operation on a table containing lots of data so I recommend not dropping constraints only to immediately create them again immediately after - you only want to create that thing once.
I chose to solve this using an anonymous code block, very similar to Mike Stankavich, however unlike Mike (who catches an error) I first check to see if the constraint exists:
DO $$
BEGIN
IF NOT EXISTS ( SELECT constraint_schema
, constraint_name
FROM information_schema.check_constraints
WHERE constraint_schema = 'myschema'
AND constraint_name = 'myconstraintname'
)
THEN
ALTER TABLE myschema.mytable ADD CONSTRAINT myconstraintname CHECK (column <= 100);
END IF;
END$$;
Using information_schema.constraint_column_usage to check for the constraint doesn't work for foreign keys. I use pg_constraint to check for primary keys, foreign keys or unique constraints:
CREATE OR REPLACE FUNCTION add_constraint(t_name text, c_name text, constraint_sql text)
RETURNS void
AS $$
BEGIN
IF NOT EXISTS(
SELECT c.conname
FROM pg_constraint AS c
INNER JOIN pg_class AS t ON c.conrelid = t."oid"
WHERE t.relname = t_name AND c.conname = c_name
) THEN
EXECUTE 'ALTER TABLE ' || t_name || ' ADD CONSTRAINT ' || c_name || ' ' || constraint_sql;
END IF;
END;
$$
LANGUAGE plpgsql;
Examples:
SELECT add_constraint('client_grant_system_scopes', 'client_grant_system_scopes_pk', 'PRIMARY KEY (client_grants_id, tenant, "scope");');
SELECT add_constraint('client_grant_system_scopes', 'client_grant_system_scopes_fk', 'FOREIGN KEY (tenant,"scope") REFERENCES system_scope(tenant,"scope") ON DELETE CASCADE;');
SELECT add_constraint('jwt_assertion_issuers', 'jwt_assertion_issuers_issuer_key', 'UNIQUE (issuer);');
Take advantage of regclass to reduce verbosity, increase performance, and avoid errors related to table naming clashes between schemas:
DO $$ BEGIN
IF NOT EXISTS (SELECT FROM pg_constraint
WHERE conrelid = 'foo'::regclass AND conname = 'bar') THEN
ALTER TABLE foo ADD CONSTRAINT bar...;
END IF;
END $$;
This will also work for tables in other schemas, e.g.:
DO $$ BEGIN
IF NOT EXISTS (SELECT FROM pg_constraint
WHERE conrelid = 's.foo'::regclass AND conname = 'bar') THEN
ALTER TABLE s.foo ADD CONSTRAINT bar...;
END IF;
END $$;
In psql You can use metacommand \gexec for run generated query.
SELECT 'ALTER TABLE xx ADD CONSTRAINT abc' WHERE not EXISTS (SELECT True FROM pg_constraint WHERE conname = 'abc') \gexec
For me those solutions didn't work because the constraint was a primary key.
This one worked for me:
ALTER TABLE <table.name> DROP CONSTRAINT IF EXISTS <constraint.name> CASCADE;
Considering all the above mentioned answers , the below approach help if you just want to check if a constraint exist in the table in which you are trying to insert and raise a notice if there happens to be one
DO
$$ BEGIN
IF NOT EXISTS (select constraint_name
from information_schema.table_constraints
where table_schema='schame_name' and upper(table_name) =
upper('table_name') and upper(constraint_name) = upper('constraint_name'))
THEN
ALTER TABLE TABLE_NAME ADD CONSTRAINT CONTRAINT_NAME..... ;
ELSE raise NOTICE 'Constraint CONTRAINT_NAME already exists in Table TABLE_NAME';
END IF;
END
$$;
Don't know why so many lines of code ?
-- SELECT "Column1", "Column2", "Column3" , count(star) FROM dbo."MyTable" GROUP BY "Column1" , "Column2" , "Column3" HAVING count(*) > 1;
alter table dbo."MyTable" drop constraint if exists "MyConstraint_Name" ;
ALTER TABLE dbo."MyTable" ADD CONSTRAINT "MyConstraint_Name" UNIQUE("Column1", "Column3", "Column2");