Should I use a compound primary key here or is UNIQUE(fk1, fk2) a better design? - sql

I am not very experienced with SQL and therefore I have troubles when it comes to decision making from time to time. What I am having are the tables shop, language and shop_supported_language.
CREATE TABLE shop (
-- PRIMARY KEY
id BIGSERIAL PRIMARY KEY
);
CREATE TABLE language (
-- PRIMARY KEY
id BIGSERIAL PRIMARY KEY,
-- ATTRIBUTES
code CHAR(5) NOT NULL,
UNIQUE (code)
);
CREATE TABLE shop_supported_language (
-- PRIMARY KEY
id BIGSERIAL PRIMARY KEY,
-- FOREIGN KEYS
shop_id BIGINT NOT NULL,
CONSTRAINT fk__shop_supported_language__shop
FOREIGN KEY (shop_id)
REFERENCES shop(id),
language_id BIGINT NOT NULL,
CONSTRAINT fk__shop_supported_language__language
FOREIGN KEY (language_id)
REFERENCES language(id)
-- Would definitely not hurt:
-- UNIQUE(shop_id, language_id)
);
As the name suggests, shop_supported_language represents the languages that a shop is actually supporting. A shop can decide in what translations it wants to provide e.g.
CREATE TABLE shop_offer_details (
-- PRIMARY KEY
id BIGSERIAL PRIMARY KEY,
-- FOREIGN KEYS
shop_offer_id BIGINT NOT NULL,
-- ...
shop_supported_language_id BIGINT NOT NULL,
CONSTRAINT fk__shop_offer_details__shop_supported_language
FOREIGN KEY (shop_supported_language_id)
REFERENCES shop_supported_language(id),
-- ...
);
Is it a good idea to not have a compound primary key for shop_supported_language? Imho it would make sense to set a UNIQUE constraint to shop_id and language_id and I'm good.
Since this is a core element in my database I would like to know if what I am doing is basically okay or fundamentally dangerous.
The reason why I don't want to use that compound PK is actually shop_offer_details. In that case I don't have to reference a compound PK. Would that be an argument against the compound PK?

If shop table has a shop_id that uniquely identifies the shop and if language table has a language_id that uniquely identifies the language and the relationship between those 2 tables is that a shop can support many languages and a language can be supported by many shops (many to many), then it should be fine to use shop_id and language_id as the 2 keys to identify what shop support what language and what language is used by what shops. I don't see a need to generate another key to identify the many to many relationship (shop_id and language_id).

There seem to be three (candidate and/or super-) key issues muddled here: PRIMARY KEY vs UNIQUE NOT NULL keys, simple vs composite keys and natural vs surrogate keys.
A PRIMARY KEY constraint is just one of whatever UNIQUE NOT NULL constraints you have that you decided to call "primary". There's no constraint difference between declaring (FK1, FK2) a PRIMARY KEY or a UNIQUE NOT NULL key. There might be project heuristics about when to use one over the other (eg declaring a key as PRIMARY KEY when it's the one to be used as FOREIGN KEY when you have a choice or having small values as keys for performance) and the DBMS might treat it differently (eg indexing it by default). There's no role for PRIMARY KEYs in relational theory.
There is also nothing wrong per se with composite keys. There are reasons for adding a simple surrogate candidate key then also using it as foreign key. Some of which are re implementation and need to be shown worth-while. And some of which are for good logical design, eg when a distinguishing id must be introduced after the system starts up or to sheild from changes in what columns are available for natural keys.

Related

What is the difference between a constraint primary key and normal primary key?

I know Its possible to use the constraint to put multiple fields like this:
CREATE TABLE Persons (
ID int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Age int,
CONSTRAINT PK_Person PRIMARY KEY (ID,LastName)
);
But If we had to compare these two below, is there is any difference?
Create table client
(cod_clt int identity not null,
Nom t,
Dn datetime not null,
Credit numeric(6,2) not null,
Constraint x1 check (credit between 100 and 1456.25),
Constraint x2 primary key (cod_clt)
)
and this:
Create table client
(cod_clt int primary key,
Nom t,
Dn datetime not null,
Credit numeric(6,2) not null,
Constraint x1 check (credit between 100 and 1456.25)
)
There's 6 classes of constraints in SQL server:
NOT NULL
Unique Key
Primary Key
Foriegn Key
Check
Default
(Some, including myself, will argue that a column Data Type and Unique indexes are also types of constraints but I digress.)
In SQL Server there are two types of constraints: Column level and Table level.
NOT NULL is a column level constraint, all the others can be table or column level. Primary and foreign keys can consist of one or more columns; when they consist of more than one column they are known as a "composite key". Composite keys must be table-level.
The most notable difference between column and table level constraints is that table level allows you to give your constraints a meaningful name which is why I personally prefer them.
In your first example you have a table level primary key constraint and it is a composite key. In your last two examples don't have a composite key which is why it can be both table and column level. The key difference in your last two examples is that you are able to name the table level primary key but not the column level one. This is a big deal for people who properly manage their metadata.
Lastly, one thing that makes Primary Key & Unique constraints are special in that, when you create them, you can create an index. The default behavior for a primary key is to also create a clustered index. The decision to create a clustered index and/or unique index is a big one so I include the keywords clustered or nonclustered when I define my primary (and unique) keys so as not to depend on default system behavior for this.
Here's a couple good links about constraints:
https://technet.microsoft.com/en-us/library/ms189862(v=sql.105).aspx - (Microsoft)
https://www.w3schools.com/sql/sql_constraints.asp (W3 Schools)

what is meaning of oracle database query: primary key references t_name(col_name)?

create table books
(
bid number(5) primary key,
name varchar2(30)
);
create table members
(
mid number(5) primary key,
name varchar2(30)
);
create table issues
(
bid number(5) primary key
references books(bid),
mid number(5)
references members (mid)
);
I have 3 tables first two tables are simple but what is the meaning of third table as I know foreign key references t_name(col_name); but what is meaning of primary key references t_name(col_name) and col_name references t_name(col_name); ?
It is no special case. Here the primary key bid of table issues is referencing to the column bid of table books. This simply means that bid of issues will have only those values which are present in bid of books. It will act as the primary key of table issues so it will have unique value and it's values will be limited to those contained in books table.
So it simply means it is primary key value with it's values in table books.
It is the same as any other references statement. This is saying that the primary key also references Books(bid).
I can think of two reasons why this type of construct would be used. First, the "issues" entity could be a subset of the "book" entity. This would allow additional issues-specific columns to be stored in issues, without cluttering up books. It also allows foreign keys to either issues or books.
The second reason is that this is one way of implementing vertical partitioning. This occurs when a table has a lots of columns. For performance reasons, you want to separate them into different storage areas. This is sort of similar to what columnar databases do, but it has the overhead of the additional primary key.

Using a foreign key as part of a composite primary key

I have two tables in SQL Server. The first is all the 1:1 relationships that belong to individual jobs, which has the primary key declared as follows:
CREATE TABLE Jobs(
JobNumber bigint PRIMARY KEY )
The second table is the list of all of the jobs' components and their 1:1 relationships.
Each component refers to a single job by its job number, which is a foreign key, and multiple components may refer to the same job. Components are numbered within jobs as 1, 2, 3 and so on.
Is it possible and reasonable to use the column JobNumber (foreign key) within a composite primary key in the 2nd table, so that the primary key would be made up of (JobNumber, ComponentNumber) as follows:
CREATE TABLE Components(
JobNumber bigint FOREIGN KEY REFERENCES Jobs(JobNumber) NOT NULL,
ComponentNumber int NOT NULL,
PRIMARY KEY(JobNumber, ComponentNumber)
)
The other option is, of course, to use a surrogate primary key, but this would not enforce the uniqueness constraint on the combination of JobNumber and ComponentNumber (two records in the 2nd table could have JobNumber=1 and ComponentNumber=1, for example), so I would prefer to use a composite natural primary key.
Sure, why not? I don't see any reason not to use the composite primary key!
The only minor drawback is that any other table that needs to reference your Components table now also must use both columns to establish a foreign key relationship - you cannot reference only half of the primary key of a table.
Also: if you would choose to use a separate surrogate column as your PK, you can always enforce uniqueness with a unique constraint on (JobNumber, ComponentNumber) ....

Duplicate Primary Keys?

Looking at an example from Java Persistence with Hibernate, there are 2 tables:
create table USERS (
USER_ID bigint not null primary key,
USERNAME varchar(15) not null unique,
NAME varchar(50) not null,
...
)
create table BILLING_DETAILS (
BILLING_DETAILS_ID bigint not null primary key,
ACCOUNT_NUMBER VARCHAR(10) not null unique,
ACCOUNT_NAME VARCHAR(50) not null,
ACCOUNT_TYPE VARCHAR(2) not null,
USER_ID bigint foreign key references USERS
)
The book mentions that the following indicates a many-to-one relationship:
USER_ID bigint foreign key references USERS
Next, it says that the following SQL statements show one-to-one associations:
USER_ID bigint unique foreign key references USERS
BILLING_DETAILS_ID bigint primary key foreign key references USERS
As I understand, the first statement means that USER_ID of the BILLING_DETAILS table will be unique and reference the primary_key of the USERS table, i.e. references USERS.
The second makes the BILLING_DETAILS_ID the primary_key and reference the USERS's primary key.
If we used both of these one-to-one relationships, then we'd have duplicate fields: USER_ID and BILLING_DETAILS_ID since they effectively are the same data?
They aren't necessarily the same data in the absence of an additional CHECK() constraint that requires user ID and billing details ID to be equal.
I have not read the book, but as a database professional, I'd consider that implementation of a one-to-one relationship to be in error. A unique constraint on billing_details.user_id, along with its obvious foreign key constraint, is sufficient to guarantee a one-to-one relationship between the two tables. (That kind of relationship doesn't make much sense in the real world, though, when you think about what billing details means.)
From a database viewpoint, letting billing_details.user_id be nullable seems questionable, too.
Later . . .
I just thought of an alternative explanation of what the book says. When it says
USER_ID bigint unique foreign key references USERS
BILLING_DETAILS_ID bigint primary key foreign key references USERS
it's describing two different ways to implement a one-to-one relationship. It's not saying you should use both statements to implement one one-to-one relationship.
But this, too, is an error, in that USER_ID isn't declared to be NOT NULL.
BILLING_DETAILS_ID is practically the primary key, which means it cannot be duplicated. However, USER_ID is NOT, you can have duplicated USER_ID in the table BILLING_DETAILS, it is treated as a data which should have a reference in the table USER.
the relationship between BILLING_DETAILS and USER is one(USER)-to-many(BILLING_DETAILS)

What is difference between foreign key and reference key?

I am very confused about those two terms. Are they the same or different?
Some books and people say they are the same and others say they are different.
I tried but couldn't find a conclusive answer.
I am supposing that you are talking about using the REFERENCES where the FOREIGN KEY keyword is not used when constraining a column inline, which is called a column-level foreign key constraint, eg.
author_id INTEGER REFERENCES author(id)
... instead of the table-level foreign key constraint, which is placed after the column declarations ...
author_id INTEGER,
FOREIGN KEY(author_id) REFERENCES author(id)
The answer is, that it is simply shorthand syntax for the same thing. The main concern when altering between the two should be readability.
For more advanced use, it might be relevant that only table-level foreign key constraints can describe constraints on multiple keys at once, where all must be present in the referenced table.
Do note that MySQL 'parses but ignores “inline REFERENCES specifications” (as defined in the SQL standard) where the references are defined as part of the column specification', meaning that only the table-level foreign key constraint will work.
Both Postgres and Microsoft's SQL Server respect both column- and table-level foreign key constraints.
A foreign key must refer to a primary key.
When using REFERENCES constraint simply, then it isn't necessary that the referenced key be a primary key.
"Reference key" isn't a normal technical term in relational modeling or in SQL implementation in US English.
A foreign key "references" a key in some other table; could that be where the confusion comes from?
You don't really call something a reference key... They are the same thing... you might see the word references used for example in sqlite: you might use syntax like this to start a db of authors and books. This lets you show that one author can have many books. This tells the db that the books.author_id (defined a couple of lines up) references author.id
CREATE TABLE 'author' (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
firstname varchar(255)
lastname varchar(255)
);
CREATE TABLE 'books' (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
author_id INTEGER,
title varchar(255),
published date,
FOREIGN KEY(author_id) REFERENCES author(id)
);
In terms of standard SQL, both result in a foreign key constraint.
One form is a table constraint, meaning it can apply to one or more columns. You would need this to reference a table that has a multi-column primary key:
CREATE TABLE child (
id int PRIMARY KEY,
parent_id int,
date date,
FOREIGN KEY (parent_id, date) REFERENCES parent(id, date)
);
The other form is a column constraint, meaning it can only apply to the single column it is defined with. It cannot be used to reference a table with a multi-column primary key.
CREATE TABLE child (
id int PRIMARY KEY,
parent_id int REFERENCES parent(id)
);
The above syntax works exactly the same as if you declared a table constraint for a single column (supposing the RDBMS supports this type of column constraint), as follows:
CREATE TABLE child (
id int PRIMARY KEY,
parent_id int,
FOREIGN KEY (parent_id) REFERENCES parent(id)
);
It frequently causes confusion for users of MySQL and its InnoDB storage engine, that the latter column-constraint style is not supported. You must define a table-level constraint for a foreign key, even if it is a single-column constraint. This has been a strange behavior of MySQL since its earliest days, that some constraint syntax is valid, but results in no constraint. See discussion here: https://bugs.mysql.com/bug.php?id=17943
The only and most important difference between the two keywords 'FOREIGN KEY" and "REFERENCES" keywords is though both of them make the data to be child data of the parent table, the "FOREIGN KEY" is used to create a table level constraint whereas REFERENCES keyword can be used to create column level constraint only. Column level constraints can be created only while creating the table only. But table level constraints can be added using ALTER TABLE command.
Perhaps you are using the term "reference key" somewhat loosely?
A foreign key value in one row is said to "reference" the row that contains the corresponding key value. Note the word "reference" in the prior sentence is a verb, so we may say we have a referencing foreign key value and a referenced key value.
Although it is the key values, rather than the table key constraint, that is being referenced, I suppose loosely speaking we could say "referenced key" to mean the rows that comprise the values that may potentially be referenced. I then see how "referenced key" could become "referenced key" but not belie its origin.
There are 2 ways to declare a foreign key(s):
if the foreign key is a SINGLE attribute:
REFERENCES ()
if foreign keys are a LIST of attributes
FOREIGN KEY () REFERENCES
A foreign key "references" a key in some other table. That key in some other table is called Referenced key. You'll probably hear a lot about this if you're using Graphic feature on phpmyadmin.
The Reference Key is the primary key that is referenced in the other table.
On the other hand, Foreign Key is how you link the second table to the primary tables Primary Key (or Reference Key).