Duplicate Primary Keys? - sql

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)

Related

Storing foreign key linked in a separate table? SQL

So I went through Odoo database design and I saw that they stored the relationship between 2 tables in a separate table that doesn't have primary key. How are you able to do this? I want to replicate this kind of behavior in SQL Server. Is it auto-inserted?
A table should always have a primary key. Look at the thousands of questions on Stackoverflow that ask how to delete one of two identical rows in a database table.
You typically model m-to-n relationships between tables with a separate table that has foreign keys to both tables:
CREATE TABLE person (
person_id bigint PRIMARY KEY,
name text,
...
);
CREATE TABLE game (
game_id bigint PRIMARY KEY,
name text NOT NULL,
...
);
CREATE TABLE likes_to_play (
person_id bigint REFERENCES person NOT NULL,
game_id bigint REFERENCES game NOT NULL,
PRIMARY KEY (person_id, game_id)
);
CREATE INDEX ON likes_to_play (game_id);
The primary key on the table makes sure there are no superfluous double entries and backs one of the foreign keys. The other index is created for the other foreign key.

Composite key for a one-to-many relationship?

For a store I have many store_offers which is a one-to-many relationship.
However, for a table
create table store (
id bigserial primary key
);
I can use a single primary key id (SQLfiddle):
create table store_offer (
id bigserial primary key,
store_id bigint not null,
constraint fk__store_offer__store
foreign key (store_id)
references store(id)
);
or a composite primary key (id, store_id) (SQLFiddle):
create table store_offer (
id bigserial not null,
store_id bigint not null,
constraint fk__store_offer__store
foreign key (store_id)
references store(id),
primary key(id, store_id)
);
My question is "what does make more sense here?". Imho the composite key should be the correct way to do it since a store_offer is actually "bound" to as store. But one can argue that this is already the case since the first version has a foreign key. On the other hand a store_offer primary key actually must not change once it's created. You have to create a new store_offer and delete the old one if you want discard one. But you cannot simply change store_id in the second approach.
So what is the correct answer here?
Using primary key(id, store_id) is a bad idea. This will make many queries more complicated and more prone to error. It sounds like what you are really trying to make is a many-to-many relationship between stores and offers. If this is the case you should have a store table with unique store_id as a primary key, an offer table with unique offer_id as a primary key and a store_offer table that has a primary key of store_id and offer_id.

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

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.

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.

Referential integrity over table portion

I'm designing a database and can't figure out how to model referential integrity.
I have the following tables
CREATE TABLE Groups
(
GroupId INT PRIMARY KEY,
GroupName VARCHAR(50)
)
CREATE TABLE GroupMembers
(
GroupId INT NOT NULL,
MemberId INT NOT NULL,
MemberName VARCHAR(50),
CONSTRAINT pk_GroupMember PRIMARY KEY (GroupId, MemberId)
)
CREATE TABLE Missions
(
MissionId INT PRIMARY KEY,
GroupId INT NOT NULL,
MissionName VARCHAR(50)
)
CREATE TABLE MissionRollAssignments
(
MissionId INT NOT NULL,
MemberId INT NOT NULL,
MemberRoll VARCHAR(50) --This will probably become RollId and move details to another table
)
Every mission will have assignments for some/all members of the corresponding group. There will be several missions associated with each group, but only one mission per group is active at a given time.
My question is:
Is it possible to enforce referenciay integrity for roll assignments such that only members
of the corresponding group (given by the MissionId) are selected? I know I can filter this from the GUI, but I'd feel more comfortable if I could create a FK constraint from MissionRollAssignments to GroupMembers while considering the GroupId indicated in the Mission.
A second question would be if you guys think this is a good way to model my domain, or maybe I should try a different approach.
Thanks in advance for any help on this.
Best regards,
Awer
You could put GroupId into MissionRollAssignments and then add two constraints as follows:
ALTER TABLE MissionRollAssignments
ADD CONSTRAINT fk1 FOREIGN KEY (GroupId, Memberid)
REFERENCES GroupMembers (GroupId, Memberid);
ALTER TABLE MissionRollAssignments
ADD CONSTRAINT fk2 FOREIGN KEY (GroupId, MissionId)
REFERENCES Missions (GroupId, MissionId);
To achieve this SQL Server first requires a (redundant) UNIQUE constraint on (GroupId, MissionId) in the Missions table. Other DBMSs are not so strict but SQL Server requires a FOREIGN KEY constraint to match exactly the columns of a uniqueness constraint.
You should use Foreign Keys to reinforce this, eg Mission.GroupId should refer to Group.GroupId.
Is it possible to enforce referenciay integrity for roll assignments such that only members of the corresponding group (given by the MissionId) are selected?
Yes. You need to use identifying relationships to propagate the GroupId all the way down to the bottom of this "diamond-shaped" dependency, similar to this:
Note FK1 and FK2 in front of MissionRollAssignment.GroupId, indicating that foreign keys exist up the both "sides" of this "diamond-shaped" dependency.
As single active mission can be modeled as a foreign key in the opposite direction, in this case as Group {GroupId, ActiveMissionNo} that references the Mission primary key.
Such circular foreign key presents a "chicken-and-egg" problem on a DBMS that doesn't support deferred constraints (which SQL Server doesn't). However, you can just leave Group.ActiveMissionNo NULL-able, so a DBMS that enforces foreign keys in a MATCH SIMPLE fashion (which SQL Server does) will ignore the whole composite foreign key if just one of its fields is NULL. This will allow you to temporarily "disable" the foreign key and break the "chicken-and-egg" cycle when inserting new data.