How to reference a postgres table with multiple primary keys - sql

How could I create a xref table with a reference to this table?
CREATE TABLE reviewer (
screen_name integer,
identity_provider text
CONSTRAINT identity PRIMARY KEY (screen_name, identity_provider)
);
This is what I've tried so far:
CREATE TABLE business_reviewer_xref (
reviewer_screen_name integer,
reviewer_identity_provider text,
CONSTRAINT reviewer_identity UNIQUE (reviewer_screen_name, reviewer_identity_provider),
reviewer_identity REFERENCES reviewer(identity)
);
CREATE TABLE business_reviewer_xref (
reviewer_screen_name integer,
reviewer_identity constraint REFERENCES reviewer(identity)
);
CREATE TABLE business_reviewer_xref (
reviewer_screen_name integer,
reviewer_identity REFERENCES reviewer(identity)
);

A table cannot have multiple primary keys. It can only have one or none. But a primary key can of course consist of more than one column (but at least of one of course). To reference such a multi column primary key, you need a corresponding column in the referencing table for each column in the primary key of the referenced column.
To define a foreign key constraint, list the corresponding columns in the referencing table in the same order as their counterparts occur in the primary key constraint in the referenced table in the defining tuple of the foreign key. Also keep the order in the definition of the referenced columns' tuple.
In your case:
CREATE TABLE business_reviewer_xref
(reviewer_screen_name integer,
reviewer_identity text,
FOREIGN KEY (reviewer_screen_name,
reviewer_identity)
REFERENCES reviewer
(screen_name,
identity));
Note that a foreign key constraint, in contrast to a primary key constraint, doesn't implicitly set a unique constraint. If you want uniqueness too, you'd have to define another constraint for that.

Related

how to set constraint and foreign key on a column

i have the below posted tables. i would like to specify a constraint and foreign key on the column called fk_grid_cell in gridCellParticularPK table.
below is my attempts, but when i execute it, it gives a syntay error
the error i am receiving is:
syntax error at `constraint`
tables:
create table if not exists grid_cell(
fourCornersTreatmentAsGeoJSON text,
fourCornersBufferAsGeoJSON text,
primary key (fourCornersTreatmentAsGeoJSON,fourCornersBufferAsGeoJSON)
)
CREATE TABLE IF NOT EXISTS grid_cell_particular (
gridCellParticularPK serial primary key,
isTreatment boolean,
isBuffer boolean,
distanceFromTreatmentToNearestEdge float8,
distanceFromBufferToNearestEdge float8,
fk_grid_cell
constraint constrains_FK_gridCell_gridCellParticular
unique foreign key references grid_cell(fourCornersTreatmentAsGeoJSON,fourCornersBufferAsGeoJSON)
)
There are few things missing:
The columns you're using for the primary key on grid_cell do not exist in the table: fourCornersOfKeyWindowRepresentativeToTreatmentAsGeoJSON and fourCornersOfKeyWindowRepresentativeToBufferAsGeoJSON.
The column names on grid_cell suggest you're storing json strings, so you should be using the data type jsonb instead of text.
The foreign key columns declared on the constraint on grid_cell_particular also do not exist on the table itself. In order to create a foreign key you must map the foreign columns to existing columns on your table. You can name them as you want, e.g. fk_grid_cell_treatment and fk_grid_cell_buffer.
Unrelated:
Consider using INDENTITY columns instead of serial. Check this out: Don't use serial
CREATE TABLE IF NOT EXISTS grid_cell(
fourCornersTreatmentAsGeoJSON jsonb,
fourCornersBufferAsGeoJSON jsonb,
fourCornersOfKeyWindowRepresentativeToTreatmentAsGeoJSON jsonb,
fourCornersOfKeyWindowRepresentativeToBufferAsGeoJSON jsonb,
PRIMARY KEY (fourCornersOfKeyWindowRepresentativeToTreatmentAsGeoJSON,
fourCornersOfKeyWindowRepresentativeToBufferAsGeoJSON)
);
CREATE TABLE IF NOT EXISTS grid_cell_particular (
gridCellParticularPK serial PRIMARY KEY,
isTreatment boolean,
isBuffer boolean,
distanceFromTreatmentToNearestEdge float8,
distanceFromBufferToNearestEdge float8,
fk_grid_cell_treatment jsonb,
fk_grid_cell_buffer jsonb,
CONSTRAINT constrains_FK_gridCell_gridCellParticular
FOREIGN KEY (fk_grid_cell_treatment,fk_grid_cell_buffer)
REFERENCES grid_cell
(fourCornersOfKeyWindowRepresentativeToTreatmentAsGeoJSON,
fourCornersOfKeyWindowRepresentativeToBufferAsGeoJSON),
CONSTRAINT unique_fk
UNIQUE (fk_grid_cell_treatment,fk_grid_cell_buffer)
);

Create table with foreign key to an other table created below in sql file

My problem is that i have two tables with each table having a foreign key to the other table.
Each time , i execute the SQL file containing the creation of the two tables, it gives me an error that he doesn't find the other table. I'm working with sqlplus to execute the sql file.
Here's an example of SQL file i tried with :
create table A(
Age number(3),
name number(3) constraint A_FK references B(name))
/
create table B(
Age number(3) constraint B_FK references A(Age),
name number(3))
And even if i reverse the order, it gives the same error.
Thanks for help.
This is a problem of cycles in foreign keys. One method is to add all foreign keys after table creation (as I think the other answers propose).
You can also just do that for the first table:
create table A (
Age number(3) primary key,
name number(3)
);
create table B (
name number(3) primary key,
Age number(3),
constraint B_FK foreign key (age) references A(Age)
);
alter table B add constraint A_FK foreign key (name) references B(name);
Here is a db<>fiddle.
Notes:
Foreign keys should reference primary keys, so I added that declaration as well.
I recommend making the primary key the first column in the table.
You can also define the constraint inline for one of the tables (i.e. age number(3) constraint b_fk references a(age)).
The table column(s) that is referred by a foreign key must exist at the time when the constraint is created. Since you have some kind of cyclic reference between the tables, you need to do this in three steps:
first create one table without the foreign key
create the second table (with its foreign key)
finally add the foreign key to the first table with an alter table statement
You also need the referred column to have a unique or primary key constraint set up, otherwise you would get error ORA-02270: no matching unique or primary key for this column-list.
create table A(
age number(3) primary key,
name number(3)
);
create table B(
age number(3) constraint B_FK references A(Age),
name number(3) primary key
);
alter table A add constraint A_FK foreign key (name) references B(name);
Demo on DB Fiddle
Side note: I am quite suspicious about your sample structure, but this could be because your oversimplified it in the question.
It fails because the reference table doesn't exist yet.
Create the tables without the key first. Then drop one and recreated it with the reference. Then drop the 2nd and recreate it with the reference.
Create table first and then ADD the CONSTRAINT
ALTER TABLE A
ADD FOREIGN KEY (name) REFERENCES B(name);
ALTER TABLE B
ADD FOREIGN KEY (age) REFERENCES A(age);

Required to Declare Primary Keys on Junction Table?

In a junction table made up of only foreign keys (e.g. ShopSupplier in the example below), must we also declare those columns as primary keys in the DDL create statement? If yes, what would be the point of doing so? I would argue that these are NOT primary keys in the example below
CREATE TABLE Shop
(
ShopID TEXT PRIMARY KEY UNIQUE,
ShopName TEXT
);
CREATE TABLE Supplier
(
SupplierID TEXT PRIMARY KEY UNIQUE,
SupplierName TEXT
);
CREATE TABLE ShopSupplier
(
ShopID TEXT,
SupplierID TEXT,
FOREIGN KEY(ShopID) REFERENCES Shop(ShopID),
FOREIGN KEY(SupplierID) REFERENCES Supplier(SupplierID)
);
The question again: Should I also declare PRIMARY KEY(ShopID, SupplierID) for the ShopSupplier table. If so, why? I would argue that there should be no primary key for that table.
Both columns are foreign key, because they are referencing to other tables. In the case that only single connection between specific rows of Shopand Supplier may exit, you can use a unique constraint or create a combined primary key:
CREATE TABLE ShopSupplier(
ShopID TEXT,
SupplierID TEXT,
PRIMARY KEY(ShopID, SupplierID),
FOREIGN KEY(ShopID) REFERENCES Shop(ShopID),
FOREIGN KEY(SupplierID) REFERENCES Supplier(SupplierID));
Then, both columns are foreign keys and belonging to the primary key.
In general setting the columns of a (pure) junction table as primary key isn't necessary. You may use it as a constraint to prohibit duplicates.

Why this UNIQUE constraint is needed?

I am trying to design schema in PostgreSQL that will contain two tables cross referencing each other. Yet if do not add redundant UNIQUE constrain (see code below) i am getting error: ERROR: there is no unique constraint matching given keys for referenced table "nodes".
So my question is: why this extra unique constraint is needed and is there a way to avoid it creation? (to reduce runtime overhead).
CREATE TABLE objects (
object_id serial NOT NULL PRIMARY KEY,
root_node integer
);
CREATE TABLE nodes (
node_id integer NOT NULL PRIMARY KEY,
object_id integer REFERENCES objects
);
ALTER TABLE objects
ADD CONSTRAINT root_node_fkey
FOREIGN KEY (root_node) REFERENCES nodes(node_id);
-- Why this constaint is needed? Since node_id is primary key this combination should be already UNIQUE
ALTER TABLE nodes ADD CONSTRAINT node_id_object_id_unique UNIQUE (node_id, object_id);
ALTER TABLE objects
ADD CONSTRAINT objects_nodes_fkey
FOREIGN KEY (object_id, root_node)
REFERENCES nodes (object_id, node_id);
https://www.postgresql.org/docs/current/static/ddl-constraints.html says:
5.3.5. Foreign Keys:
. . .
A foreign key must reference columns that either are a primary key or form a unique constraint. This means that the referenced columns always have an index (the one underlying the primary key or unique constraint); so checks on whether a referencing row has a match will be efficient.
https://mariadb.com/kb/en/sql-99/constraint_type-foreign-key-constraint/ says:
A FOREIGN KEY Constraint is either a < Table Constraint> or a and defines a rule that constrains a foreign key to values that match only those values contained in a referenced unique key.
Re your comment:
The idea is that each object will have collections of nodes associated with it and only one of nodes could be the root-node.
ALTER TABLE objects
ADD COLUMN root_node_id integer,
ADD CONSTRAINT objects_nodes_fkey
FOREIGN KEY (root_node_id)
REFERENCES nodes (node_id);
That way each object references exactly one node. Admittedly, constraint doesn't strictly enforce that an object references a node that references the same object.
If you want that level of enforcement, you'll have to create the unique constraint you were asking if you had to.

There are no PK in the referenced table. Why?

I have the following T-SQL to create 3 SQL tables:
create table dbo.Posts
(
Id int identity not null
constraint PK_Posts_Id primary key clustered (Id),
Active bit not null
constraint DF_Posts_Active default (0)
);
create table dbo.PostsLocalized
(
Id int not null,
Culture int not null
constraint CK_PostsLocalized_Culture check ([Culture] in ('1', '2', '3')),
[Text] nvarchar (200) not null,
constraint PK_PostsLocalized_Id_Culture primary key clustered (Id, Culture)
);
create table dbo.Tags
(
Id int identity not null
constraint PK_Tags_Id primary key clustered (Id),
Name nvarchar not null
);
create table dbo.PostsLocalized_Tags
(
PostLocalizedId int not null,
TagId int not null,
constraint PK_PostsLocalized_Tags_Post_PostLocalizedId_TagId primary key clustered (PostLocalizedId, TagId)
);
Then I have added the following constraints:
alter table dbo.PostsLocalized
add constraint FK_PostsLocalized_Id foreign key (Id) references dbo.Posts(Id) on delete cascade on update cascade;
alter table dbo.PostsLocalized_Tags
add constraint FK_PostsLocalized_Tags_PostLocalizedId foreign key (PostLocalizedId) references PostsLocalized(Id) on delete cascade on update cascade,
constraint FK_PostsLocalized_Tags_TagId foreign key (TagId) references Tags(Id) on delete cascade on update cascade;
But I get the following error:
There are no primary or candidate keys in the referenced table 'PostsLocalized' that match the referencing column list in the foreign key 'FK_PostsLocalized_Tags_PostLocalizedId'.
How can I solve this?
Thank You,
Miguel
SQL Server mandates that foreign key references be to a primary key or unique key. The foreign key reference has to be to all the columns that constitute the primary/unique key. The documentation says:
In a foreign key reference, a link is created between two tables when
the column or columns that hold the primary key value for one table
are referenced by the column or columns in another table. This column
becomes a foreign key in the second table.
A FOREIGN KEY constraint does not have to be linked only to a PRIMARY
KEY constraint in another table; it can also be defined to reference
the columns of a UNIQUE constraint in another table. A FOREIGN KEY
constraint can contain null values; however, if any column of a
composite FOREIGN KEY constraint contains null values, verification of
all values that make up the FOREIGN KEY constraint is skipped. To make
sure that all values of a composite FOREIGN KEY constraint are
verified, specify NOT NULL on all the participating columns.
The primary key in PostsLocalized contains the culture column, so you need to add it into the foreign key reference.
Your PK on PostsLocalized table is complex consisting of two columns - id and culture and you are trying to create FK on only one of those columns which is not possible.
You'll have to either add Culture column on PostsLocalized_Tags and use them both in foreign key or remove Culture from your PK on PostLocalized