Prevent row insertion if foreign_key is not null in the referenced row - sql

Simple table with primary key as the first column and foreign key referencing the same table as the second column.
1 | null
2 | 1
I want to prevent insertion of a row whose fk would reference a row whose fk is not null. E.g. insertion of the row below should be prevented:
3 | 2
How can it be achieved? I'v tried the following
ALTER TABLE t
ADD CONSTRAINT t_check
CHECK (
fk not in (select t.pk from t1 t where t.pk = fk and t.fk is not null)
);
but got
ERROR: cannot use subquery in check constraint
as expected.

Related

pgsql how to enforce uniqueness for some keys

I have two tables. table1 has attributes unique or not
attribute_id uniqueness
1 no
2 yes
3 yes
Table 2 has below data, there is unique constraint on combined columns object_id and attribute_id .
Now I need another unique constraint on value column for some attribute_id has uniqueness=yes.
Like, attribute_id 2 and 3 has unique=yes in table1. they can't have duplicate values in table2.
auto_id object_id attribute_id value
1 1 1 a
2 2 1 a
3 1 2 b
4 2 2 d
We can't insert (attribute_id,value)=(2,b) or (2,d) and it should through error duplicate key value violates unique constraint if we try to insert dup values.
I hope we can do this by trigger but it will be very slow.
Looking for better approach, any possible solution pls ?
The only way to do that with a constraint that I can think of is this:
add the uniqueness column to table2 too and fill it with the proper value
define a UNIQUE constraint on table1(attribute_id, uniqueness)
define a foreign key constraint on table2:
ALTER TABLE table2 ADD FOREIGN KEY (attribute_id, uniqueness)
REFERENCES table1 (attribute_id, uniqueness);
define a partial unique index on table2:
CREATE UNIQUE INDEX ON table2 (attribute_id, value) WHERE uniqueness;
Of course this will lead to data duplication, but the foreign key will guarantee that no inconsistencies can occur.

How do i Update data in table from other table with condition

i have 2 tables and both has one column as a primary and foreign key. i have to update one table column which is empty but the primary table has the values which needs to be updated here. how do i update that particular column by referencing those columns of primary table in foreign-key table?
Table 1 - Primary -Column list
SI.No (PrimaryKey)
UpdateTime
StudentDetail
table 2 - Foreign - Column list
SI.No(ForeignKey)
UpdateTime
BatchCode
Table 2 of updateTime is empty for some students due to some reason. I need to get the update time from table 1 of those empty students and update it to table 2. how do i do this?? using postgress i am.
In Postgres, you can use a FROM clause to reference another table:
update table2 t2
set updatetime = t1.updatetime
from table1 t1
where t1.sl_no = t2.sl_no and t2.updatetime is null;

How to add new foreign key column with default value to an existing table with data

I'm trying to achieve this:
Table A that has almost 100 records - to add a new column (eg: ID
with default value 0)
Creating a new table B for which ID is PK
I tried this:
added ID column to Table A as null
updated the old values as 0 for existing rows
created Table B with ID as PK
made ID column as not null in Table A
tried to add FK constraint to Table A
And got this error:
ORA-02298: cannot validate parent keys not found.
What am I missing here? Also, I cannot delete child records in Table A
According to this Ask TOM article : Constraint ENABLE/ DISABLE
You can enable or disable integrity constraints at the table level
using the CREATE TABLE or ALTER TABLE statement. You can also set
constraints to VALIDATE or NOVALIDATE, in any combination with ENABLE
or DISABLE
And from a related artice by Tim Hall: ORACLE-BASE
ENABLE VALIDATE is the same as ENABLE. The constraint is checked and is guaranteed to hold for all rows.
ENABLE NOVALIDATE means the constraint is checked for new or modified rows, but existing data may violate the constraint.
DISABLE NOVALIDATE is the same as DISABLE. The constraint is not checked so data may violate the constraint.
DISABLE VALIDATE means the constraint is not checked but disallows any modification of the constrained columns.
So, to answer your question
"How to add new foreign key column with default value to an existing
table with data"
you may use option 2 ONLY if you want that the constraint is checked, but it does not have to be
true for all rows. This allows existing rows to violate the constraint, while ensuring
that all new or modified rows are valid.
ALTER TABLE A ADD FOREIGN KEY (ID) REFERENCES B(ID) ENABLE NOVALIDATE;
Starting scenario - CHILD_TABLE with 100 rows and no link to PARENT_TABLE:
create table parent_table (id integer constraint parent_pk primary key);
create table child_table (somecolumn integer);
insert into child_table select rownum from dual connect by rownum <= 100;
Now we want to link CHILD_TABLE to PARENT_TABLE with the default parent set to 0.
Add a value to PARENT_TABLE so that CHILD_TABLE can refer to it:
insert into parent_table (id) values (0);
If you don't add this value, it's like having a VEHICLES table with the default manufacturer as 'HONDA', but not defining 'HONDA' in the MANUFACTURERS table. The whole point of foreign keys is to stop you doing that.
Now add a foreign key to CHILD_TABLE (default on null is new in Oracle 12.1, but the plain default also works, however only recent versions of Oracle apply the default when adding a new column - I forget which version exactly.)
alter table child_table
add parent_id integer
default on null 0
constraint child_parent_fk references parent_table ;
Check what we have in CHILD_TABLE now:
select * from child_table;
SOMECOLUMN PARENT_ID
---------- ---------
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 0
9 0
10 0
11 0
...
100 rows selected
Check the status of the new FK:
select fk.constraint_name, fkc.column_name, fk.status
, pk.table_name, fk.r_constraint_name
from user_constraints fk
join user_constraints pk
on pk.constraint_name = fk.r_constraint_name
and pk.owner = fk.r_owner
join user_cons_columns fkc
on fkc.table_name = fk.table_name
and fkc.constraint_name = fk.constraint_name
where fk.table_name = 'CHILD_TABLE'
and fk.constraint_type = 'R'
and pk.constraint_type = 'P';
CONSTRAINT_NAME COLUMN_NAME STATUS TABLE_NAME R_CONSTRAINT_NAME
------------------ ------------------- -------- ------------------- -----------------
CHILD_PARENT_FK PARENT_ID ENABLED PARENT_TABLE PARENT_PK

How to create SQL constraint on primary key to make sure it could only be referenced once?

How do I add constraint to guard that a primary key could only be referenced once?(It could be referenced in two tables)
Each reference should have a unique value out of the primary key.
Table A
----------------------
id
1
2
3
4
Table B
----------------------
id a_id (foreign key to table A.id)
1 2
2 3
Table C
----------------------
id a_id (foreign key to table A.id)
1 1
I want something to happen to give error when try to insert a_id = 2 into table C as its used in table B already.
You can use an INSERT, UPDATE trigger on each of the child tables to ensure that the PK of the parent table that is about to be inserted or updated does not already exist in the other child table.
What you are trying to do requires another table D, that will help unify the references to A.
Table D will contain its own primary key ( Id ), a reference to table A with a UNIQUE constraint on it (call it AId ), and a third column (called "RowType") to indicate to which of the child tables (B or C) the row corresponds. You can make this column to be of type int, and assign value "0" for B and "1" for C, for example.
Then in table B you add a foreign key to D.Id, AND another column "BRowType" as foreign key to D.RowType; then you define a constraint on this column, so it can only have the value '0' ( or whatever value you have decided to correspond to this table).
For table C your constraint will limit the values to '1'.
Or course, in order to insert a record into B or C you first need to create a record in D. But once you have a record in B that references a record in D, which in turn links to a record in A, you will no longer be able to create a record in C for the same line in A - because of the UNIQUE constraint on D.AId AND the constraint on C.BRowType.
If I understand the question correctly, it sounds like you need to add a unique constraint on the column of each table that references your primary key.
For example:
Table A
----------------------
id (primary key)
1
2
3
Table B
----------------------
id a_id (foreign key to table A.id)
1 2
2 3
Set the a_id column to be UNIQUE and that way you can ensure that the primary key from Table A is not used twice. You would do that in each table which references A.id
If you want to avoid using triggers, you could create a table X with id and a unique constraint on it.
In each transaction in which you insert a record into B or C you have to insert into X as well. Both insertions will only be possible if not yet in the other table.

How to update rows of two tables that have foreign key restrictions

I have two tables: one is foreign reference table lets say table a and other one is the data table lets say table b.
Now, when I need to change the data in table b, but I get restricted by table a.
How can I change "rid" in both tables without getting this message?
"ERROR: insert or update on table "table a" violates foreign key
constraint "fk_boo_kid" SQL state: 23503
Detail: Key (kid)=(110) is not present in table "table b".
Example query to update both tables:
UPDATE table b table a SET rid = 110 WHERE rid =1
table b
+-----+-------+-------+
| rid | ride | qunta |
+-----+-------+-------+
| 1 | car | 1 |
| 2 | bike | 1 |
+-----+-------+-------+
table a
+-----+-----+------------+
| kid | rid | date |
+-----+-----+------------+
| 1 | 1 | 20-12-2015 |
| 2 | 2 | 20-12-2015 |
+-----+-----+------------+
In Postgres you can use a writeable CTE to update both tables in a single statement.
Assuming this table setup:
create table a (rid integer primary key, ride text, qunta integer);
create table b (kid integer primary key, rid integer references a, date date);
The CTE would be:
with new_a as (
update a
set rid = 110
where rid = 1
)
update b
set rid = 110
where rid = 1;
As (non-deferrable) foreign keys are evaluated on statement level and both the primary and foreign key are changed in the same statement, this works.
SQLFiddle: http://sqlfiddle.com/#!15/db6d1/1
you can not update/delete primary key in table B, because the primary key is used in table A.
you can delete primary key in table B, IF >>
you must delete the row in table A which is used primary key table B.
you can delete the row in table B
you have to change both manual
SET session_replication_role = 'replica';
UPDATE table a SET rid=110 WHERE rid=1 ;
UPDATE table b SET rid=110 WHERE rid=1 ;
SET session_replication_role = 'origin';
This is too long for a comment.
You should really explain why you want to change ids into something else. Primary keys really should be considered immutable, so they identify rows both within a table and over time.
If you do need to change them for some reason, then define proper foreign key constraints for the tables in question. Then define the foreign keys to be on update cascade. This will "cascade" changes to all affected changes when a primary key changes.