How to manage postgresql foreign keys? - sql

I need some advice on SQL structure on Postgresql.
I have those two tables :
DROP TABLE IF EXISTS "public"."attribute_value";
CREATE TABLE "public"."attribute_value"
(
"id" INTEGER NOT NULL,
"attribute_id" INTEGER NOT NULL,
"value" CHARACTER VARYING(100) NULL
);
--*****************************************************
DROP TABLE IF EXISTS "public"."product_attribute";
CREATE TABLE "public"."product_attribute"
(
"product_id" INTEGER NOT NULL,
"attribute_value_id" INTEGER NOT NULL,
"attribute_id" INTEGER NOT NULL
);
I added no constraints on purpose.
I need a foreign key on the child table product_attribute.attribute_value_id referencing the parent table attribute_value.id. The best practice is to create a primary key on the field attribute_value.id (maybe with a sequence), or to CREATE UNIQUE INDEX on attribute_value.id ?
I first thought indexes were only special lookup tables that the database search engine can use to speed up data retrieval. But when I played with foreign keys, I found that creating an unique index allowed me to avoid error "there is no unique constraint matching given keys for referenced table blablabla" because a foreign key is not supposed to point to a non unique value. Should indexes be used to create foreign keys then ?
I also need a foreign key on the child table product_attribute.attribute_id referencing parent table attribute_value.attribute_id. The problem is that attribute_value.attribute_id is not unique. But all the rows in product_attribute.attribute_id must not take any value out of attribute_value.attribute_id's possible values. How should I do ?

Every table should have a primary key. Don't join the legion of people who complain about duplicate rows in their tables.
So make id the primary key of attribute_value, then you can create a foreign key constraint.
Constraints are implemented by unique indexes, so technically they are almost the same. Still you need a constraint and not just a unique index as the target of a foreign key constraint.
About attribute_id: that should not be a foreign key constraint between the two tables from your question, but both tables should have a foreign key referencing yet another table (attribute?).

Related

Away around Error: There is no unique constraint matching given keys for referenced table

Been at this for some time now. I'm getting this psql error when attepmting to create a joins table (product_type_combo):
There is no unique constraint matching given keys for referenced table product
I'm receiving this because the field (customer) I'm referencing from the table product does not have a UNIQUE constraint.
CREATE TABLE product
(
id SERIAL PRIMARY KEY,
name VARCHAR(128) NOT NULL,
customer VARCHAR,
CONSTRAINT product_c01 UNIQUE (name)
);
CREATE TABLE product_type_combo
(
customer VARCHAR REFERENCES product(customer),
type_id INT REFERENCES type(id),
PRIMARY KEY (customer, type_id),
CONSTRAINT product_type_combo_c01 UNIQUE (customer, type_id)
);
I don't want to have a UNIQUE constraint on the customer field on the product table since I want duplicates to appear there. I only want the customer & type combo in the joins table to have a constraint.
Is there a way around this?
This is silly:
customer VARCHAR REFERENCES product(customer),
You have a primary key on the table, an id column. You should be using that.
You could define customer to be unique -- the lack of a unique constraint on a column used for a foreign key reference is the cause of the error. However, I strongly, strongly recommend that you use the primary key.
The error is coming from the Foreign Key (REFERENCES) constraint, for reasons listed in the PostgreSQL manual:
A foreign key must reference columns that either are a primary key or form a unique constraint.
Since your "customer" column is not unique, it cannot be the target of a foreign key reference. It also suggests a problem in your data model:
If the relationship is between a product and a type, then referencing the "id" from the products table would make sense.
If the relationship is between a customer and a type, then there should be a table listing all the possible customers, and you can create foreign keys referencing that from both "product" and "product_type_combo" (which would presumably be better named "customer_type_combo").

Is it possible to create one index for both primary and foreign key?

Let's suppose we have two tables A and B and between them one-to-one relation.
CREATE TABLE IF NOT EXISTS A
(
ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (ID)
);
CREATE TABLE IF NOT EXISTS B
(
ID INT UNSIGNED NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (ID) REFERENCES A(ID)
ON UPDATE CASCADE ON DELETE CASCADE
);
B.ID key will be used as foreign key in tables about which A doesn't know. When row is deleted from A there also will be deletion from other tables that are linked to B. As we see in B one column is at the same time primary and foreign key. As I know keys use indexes. So, is it possible to make these two keys use the same index? Does it depend on RDBMS? Or there is something wrong in my understanding?
As I know [foreign] keys use indexes
This is false. I am guessing that your experience with databases is limited to MySQL/MariaDB. These are two databases where a foreign key definition does created an index on the referencing table.
In most databases, a foreign key definition does NOT create an index on the referencing table. Another difference is that most databases (and I'm pretty sure the standard as well) requires that the referenced key be either a primary key or unique key. That doesn't affect you in this case, but it is another deviation from the standard in MySQL in this area.

Can FOREIGN KEY be omitted in PostgreSQL when using REFERENCES?

I'm wondering if there's any (maybe subtle) difference between these two SQL statements:
CREATE TABLE profiles (
profile_id SERIAL PRIMARY KEY NOT NULL,
bio TEXT,
user_id INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(user_id)
);
and
CREATE TABLE profiles (
profile_id SERIAL PRIMARY KEY NOT NULL,
bio TEXT,
user_id INTEGER NOT NULL REFERENCES users(user_id)
);
I've noticed that when I create a table in Postico with the first notation, but look at the DDL of the created profiles table later, the FOREIGN KEY is removed and I end up with the shorter second notation.
Create table with FOREIGN KEY:
DDL view doesn't show FOREIGN KEY:
So, I'm wondering (and seeking confirmation) that the two statements are in fact 100% equivalent or if there are some subtle differences in what they do to the DB.
Any pointer to official resources (and maybe also how that differs from MySQL) would be appreciated.
The two samples you show do the same thing, just with a different syntax.
The first method is called table constraint, the second column constraint, but the latter name is somewhat misleading because the constraint is on the table as well.
The main difference is that the column constraint syntax is shorter, but cannot be used for all constraints: if you have for example a primary key that contains two columns, you have to write it in the table constraint syntax.
DDL view doesn't show FOREIGN KEY
DDL view created by unknown third-party tool in not an argument.
See fiddle. Foreign key exists in both cases. Moreover, I do not see the result difference for both DDL queries.
PS. As a recommendation - always specify the constraint name explicitly. What if you need to delete it? It is problematic without the constraint name...
In PostgreSQL, you define a foreign key through a foreign key constraint. A foreign key constraint indicates that values in a column or a group of columns in the child table match with the values in a column or a group of columns of the parent table. We say that a foreign key constraint maintains referential integrity between child and parent tables.
This may explain to you better or you can read about Foreign Keys documentation .

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.

SQL - Unique Key, Primary Key & Foreign Key

What are the differences between Unique Key, Primary Key and Foreign Key with respect to concept of SQL?
How they are different from each other?
A PRIMARY Key and UNIQUE Key constraints both are similar and it provide unique enforce uniqueness of the column on which they are defined.
Primary Key
Primary key cannot have a NULL value.
Each table can have only one primary key.
By default, Primary key is clustered index and data in the database table is physically organized in the sequence of clustered index.
Primary key can be related with another table's as a Foreign Key.
We can generated ID automatically with the help of Auto Increment field. Primary key supports Auto Increment value.
Unique Key
Unique Constraint may have a NULL value.
Each table can have more than one Unique Constraint.
By default, Unique key is a unique non-clustered index.
Unique Constraint can not be related with another table's as a Foreign Key.
Unique Constraint doesn't supports Auto Increment value.
Foreign Key
Foreign key is a field in the table that is primary key in another table.
Foreign key can accept multiple null value.
Foreign key do not automatically create an index, clustered or non-clustered. You can manually create an index on foreign key.
We can have more than one foreign key in a table.
There are actual advantages to having a foreign key be supported with a clustered index, but you get only one per table. What's the advantage? If you are selecting the parent plus all child records, you want the child records next to each other. This is easy to accomplish using a clustered index.
Having a null foreign key is usually a bad idea. In the example below, the record in [dbo].[child] is what would be referred to as an "orphan record". Think long and hard before doing this.
Note: we use constraint for enforce data integrity
Primary Key
1)can't insert null value
2) one table have one primary key
Unique key
1) insert null value one at time
2)one table have multiple unique key
3) you can refereed as candidate key also
foreign key
1) maintain the relationship between two table and also multiple
Note: without any constraint you get data in multiple table but you can not get data peoperly
A note about Unique key
The parent table in a Primary Key-Foreign Key relation is normally called as Primary Key table but PK is not mandatory in a parent table. A unique key/constraint in parent table is sufficient. As PK is always unique, it is often used as foreign key in another table. see this SO post