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.
I've found a million things sounding kind of similar on StackOverflow, but not my case exactly. I'll simplify as much as possible:
I have two tables as follows:
CREATE TABLE B (id uuid PRIMARY KEY);
CREATE TABLE A (id uuid PRIMARY KEY, b_id uuid REFERENCES b);
There are some NULL values in A.b_id. I am trying to create a migration that does the following:
For every row in A with no b_id, create a new row in B, and assign its id to A.b_id.
How can I accomplish this in one query?
Assuming you want a distinct entry in b for every row with a missing UUID in a:
WITH upd AS (
UPDATE a
SET b_id = gen_random_uuid()
WHERE b_id IS NULL
RETURNING b_id
)
INSERT INTO b (id)
SELECT b_id FROM upd;
db<>fiddle here
This works because it's a single command, and the FK reference is only enforced at the end of the command.
See:
SET CONSTRAINTS ALL DEFERRED not working as expected
Constraint defined DEFERRABLE INITIALLY IMMEDIATE is still DEFERRED?
We have table A. Table B has foreign key to A. And now, if there is already a row in table B with attribute surname="Jordan" that has foreign key relation to a particular row in A , it will be impossible to create another row in table B with the same surname that will have relation with the same row in A.
How to solve this problem.
Create a unique index on Table B's foreign key column.
Note that this suggests Table B should probably be folded into Table A.
This isn't a big deal, but my OCD is acting up with the following problem in the database I'm creating. I'm not used to working with databases, but the data has to be stored somewhere...
Problem
I have two tables A and B.
One of the datafields is common to both tables - segments. There's a finite number of segments, and I want to write queries that connect values from A to B through their segment values, very much asif the following table structure was used:
However, as you can see the table Segments is empty. There's nothing more I want to put into that table, rather than the ID to give other table as foreign keys. I want my tables to be as simple as possible, and therefore adding another one just seems wrong.
Note also that one of these tables (A, say) is actually master, in the sense that you should be able to put any value for segment into A, but B one should first check with A before inserting.
EDIT
I tried one of the answers below:
create table A(
id int primary key identity,
segment int not null
)
create table B(
id integer primary key identity,
segment int not null
)
--Andomar's suggestion
alter table B add constraint FK_B_SegmentID
foreign key (segment) references A(segment)
This produced the following error.
Maybe I was somehow unclear that segments is not-unique in A or B and can appear many times in both tables.
Msg 1776, Level 16, State 0, Line 11 There are no primary or candidate
keys in the referenced table 'A' that match the referencing column
list in the foreign key 'FK_B_SegmentID'. Msg 1750, Level 16, State 0,
Line 11 Could not create constraint. See previous errors.
You can create a foreign key relationship directly from B.SegmentID to A.SegmentID. There's no need for the extra table.
Update: If the SegmentIDs aren't unique in TableA, then you do need the extra table to store the segment IDs, and create foreign key relationships from both tables to this table. This however is not enough to enforce that all segment IDs in TableB also occur in TableA. You could instead use triggers.
You can ensure the segment exists in A with a foreign key:
alter table B add constraint FK_B_SegmentID
foreign key (SegmentID) references A(SegmentID)
To avoid rows in B without a segment at all, make B.SegmentID not nullable:
alter table B alter column SegmentID int not null
There is no need to create a Segments table unless you want to associate extra data with a SegmentID.
As Andomar and Mark Byers wrote, you don't have to create an extra table.
You can also CASCADE UPDATEs or DELETEs on the master. Be very carefull with ON DELETE CASCADE though!
For queries use a JOIN:
SELECT *
FROM A
JOIN B ON a.SegmentID = b.SegmentID
Edit:
You have to add a UNIQUE constraint on segment_id in the "master" table to avoid duplicates there, or else the foreign key is not possible. Like this:
ALTER TABLE A ADD CONSTRAINT UNQ_A_SegmentID UNIQUE (SegmentID);
If I've understood correctly, a given segment cannot be inserted into table B unless it has also been inserted into table A. In which case, table A should reference table Segments and table B should reference table A; it would be implicit that table B ultimately references table Segments (indirectly via table A) so an explicit reference is not required. This could be done using foreign keys (e.g. no triggers required).
Because table A has its own key I assume a given segment_ID can appear in table A more than once, therefore for B to be able to reference the segment_ID value in A then a superkey would need to be defined on the compound of A_ID and segment_ID. Here's a quick sketch:
CREATE TABLE Segments
(
segment_ID INTEGER NOT NULL UNIQUE
);
CREATE TABLE A
(
A_ID INTEGER NOT NULL UNIQUE,
segment_ID INTEGER NOT NULL
REFERENCES Segments (segment_ID),
A_data INTEGER NOT NULL,
UNIQUE (segment_ID, A_ID) -- superkey
);
CREATE TABLE B
(
B_ID INTEGER NOT NULL UNIQUE,
A_ID INTEGER NOT NULL,
segment_ID INTEGER NOT NULL,
FOREIGN KEY (segment_ID, A_ID)
REFERENCES A (segment_ID, A_ID),
B_data INTEGER NOT NULL
);
i have table A and table B. I have a bridge table called tableC
in table C i have:
ID
tableA_ID
tableB_ID
ID is the primary key.
i also want to enforce the combination of tableA_ID and tableB_ID to be unique so there are no duplicate records.
how do i enforce this?
create unique index myIdx on tableC(tableA_ID, tableB_ID)
or whatever the syntax for your particular database system is.
Make the PRIMARY KEY tableA_ID and tableB_ID, EXCLUDING ID
lets say we have a table TABLEA with values
tableAID
1
2
3
and table TABLEB with values
tableBID
4
5
6
making the primary key (ID, tableA_ID, tableB_ID) will not work eg.
ID | tableAID | tableBID
1 | 1 | 4
2 | 1 | 4
will work fine with the above pk, but you need PRIMARY KEY (tableA_ID, tableB_ID)
Drop the ID column then make the other two columns the primary key and their uniqueness will be enforced by the database server.
It's not really necessary to have the ID column - even though it serves as a handy way of referencing a particular record - as the uniqueness of the other two columns will mean that they are sufficient to reference a particular record.
You may also want to put an index on this table, that includes bothe columns, to make access faster.