Transforming into Normal Form - sql

There are zones, avatars and instances of zones. Avatar must belong to zero or one instance for each zone.
CREATE TABLE zones (
id SERIAL NOT NULL PRIMARY KEY,
name VARCHAR NOT NULL,
...
);
CREATE TABLE avatars (
id SERIAL NOT NULL PRIMARY KEY,
...
);
CREATE TABLE instances (
id SERIAL NOT NULL PRIMARY KEY,
zone_id INTEGER REFERENCES zones NOT NULL,
...
);
CREATE TABLE avatar_instances (
avatar_id INTEGER REFERENCES avatars NOT NULL,
zone_id INTEGER REFERENCES zones NOT NULL,
instance_id INTEGER REFERENCES instances NOT NULL,
PRIMARY KEY(avatar_id, zone_id)
);
I'm not happy with the schema above, because zone_id in each record in avatar_instances has to agree with the zone_id inside of the respective instances row.
Ideally I'd like a unique index on avatar_instances which "reaches inside" of the instances table to see instances.zone_id.
e.g.
CREATE TABLE avatar_instances (
avatar_id INTEGER REFERENCES avatars NOT NULL,
instance_id INTEGER REFERENCES instances NOT NULL,
PRIMARY KEY(avatar_id, instance.zone_id)
);
How can I transform this schema into Nth normal form, while preserving the restriction that 'each avatar must belong to zero or one instance for each zone'?

Create a unique and add a composite FK referencing unique.
CREATE TABLE instances (
id SERIAL NOT NULL PRIMARY KEY,
zone_id INTEGER REFERENCES zones NOT NULL,
UNIQUE (zone_id, id)
);
CREATE TABLE avatar_instances (
avatar_id INTEGER REFERENCES avatars NOT NULL,
zone_id INTEGER NOT NULL,
instance_id INTEGER NOT NULL,
CONSTRAINT fk_ai2i FOREIGN KEY (zone_id, instance_id) REFERENCES instances (zone_id, id),
PRIMARY KEY(avatar_id, zone_id)
);
Allow null in avatar_instances.instance_id if Avatar must belong to zero or one instance for each zone.

Related

References with PostgreSQL

I have this table:
CREATE TABLE cars_info.cars
(
id SERIAL,
owner_id INTEGER,
brand VARCHAR(50) NOT NULL,
model VARCHAR(50) NOT NULL,
color VARCHAR(50) NOT NULL,
register_number VARCHAR(50) NOT NULL,
created DATE NOT NULL,
PRIMARY KEY(id, brand, model, color, register_number, created),
CONSTRAINT fk_owner_id
FOREIGN KEY(owner_id)
REFERENCES persons_info.persons(id)
);
But when I tried create another table like this:
CREATE TABLE cars_info.violations
(
id SERIAL PRIMARY KEY,
car_id INTEGER NOT NULL,
message VARCHAR(100) NOT NULL,
active BOOLEAN NOT NULL,
CONSTRAINT fk_car_id
FOREIGN KEY(car_id)
REFERENCES cars_info.cars(id)
);
I get an error about that
Target external table "cars" does not have a unique constraint corresponding to the given keys
How can I fix that? I'm a beginner in SQL and don't know how to go about googling that
Your primary key definition for cars
PRIMARY KEY(id, brand, model, color, register_number, created)
makes no sense: The id column, being serial, is itself unique and it alone should be the primary key.
Delete your primary key definition and change the id column definition to:
id serial not null primary key
Unrelated, but best practice is to name table in the singular; name your tables car and violation rather than cars and violations

Design sql tables with list of foreign keys

I want to create an application for rotating pairs in a team every day. I need to store this in the database. Requirments are:
A team should be assigned to one ore more members.
Each team can have multiple tabs and different members allocate in them.(If team consist of 4 members for the particular tab only 3 should be part of it)
Each tab will have a pair of members or list of pairs per day stored.
I have ended up designing something like the example below:
create table if not exists team (
id serial not null primary key,
name text not null
);
create table if not exists member (
id serial not null primary key,
team_id integer references team(id),
nickname text
);
create table if not exists team_tab (
id bigserial not null primary key,
team_id integer references team(id) on delete cascade,
name text not null,
member_ids integer[],
);
create table if not exists team_tab_pairs (
id bigserial not null primary key,
team_tab_id integer not null references team_tab(id) on delete cascade,
tab_date date not null,
pair_ids integer[][],
);
I need an advice and suggestions how could I achieve this without having a list of references ids stored in the 2 tables below.
You need an extra table to design an M:N relationship. This is the case, for example, between "team tab" and "member". In addition to both main entities:
create table member (
id serial not null primary key,
team_id integer references team(id),
nickname text
);
create table team_tab (
id bigserial not null primary key,
team_id integer references team(id) on delete cascade,
name text not null
);
...you'll need to create a table to represent the M:N relationship, as in:
create table team_tab_member (
team_tab_id bigint not null,
member_id int not null,
primary key (team_tab_id, member_id) -- optional depending on the model
);

Postgresql multiple tables with same foreign key unique constraint

I have following tables on PostgreSQL 9.4
CREATE TABLE "user" (
id SERIAL PRIMARY KEY,
email CHARACTER VARYING NOT NULL,
password CHARACTER VARYING NOT NULL
);
CREATE TABLE "dealer" (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES "user" (id) ON DELETE RESTRICT
);
CREATE TABLE "affiliate" (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES "user" (id) ON DELETE RESTRICT
);
Is it possible to force user_id value to be unique across tables dealer and affiliate?
There are different setups to use for inheritance in SQL and for this you could just use an integer column type in the table user that marks the type of the user and would reference to table user_type (id,name) that would have the values 1,dealer and 2,affiliate:
CREATE TABLE user_type (
id INTEGER PRIMARY KEY, --could be SERIAL
name text
);
INSERT INTO user_type VALUES (1,'dealer'), (2, 'affiliate');
CREATE TABLE "user" (
id SERIAL PRIMARY KEY,
email CHARACTER VARYING NOT NULL,
password CHARACTER VARYING NOT NULL,
user_type INTEGER REFERENCES user_type NOT NULL,
UNIQUE(id,user_type)
);
This in itself wouldn't force uniqueness across tables so after implementing this you would have the following options:
Drop the tables dealer and affiliate - you won't need them if you rely on the type field to see which one the user is.
If you have to keep those inherited tables you can:
Use triggers - these triggers check the uniqueness and would be actived on INSERT or UPDATE
Another (a bit clumsy) solution: add user_type field to both subtables like this:
CREATE TABLE "dealer" (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
user_type INTEGER NOT NULL DEFAULT 1 check (user_type = 1),
FOREIGN KEY (user_id,user_type) REFERENCES "user"(id,user_type) ON DELETE RESTRICT
);
CREATE TABLE "affiliate" (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
user_type INTEGER NOT NULL DEFAULT 2 check (user_type = 2),
FOREIGN KEY (user_id,user_type) REFERENCES "user"(id,user_type) ON DELETE RESTRICT
);
The checks and foreign keys together make sure you cannot have both types of user in the main table. Note that user_id might be used as the PRIMARY KEY in the subtables too. Currently a row in user might have several dealer rows linked to it so at least you might want to set user_id foreign keys in subtables as UNIQUE.

Error: Could not create constraint SQL Server 2008

I am creating 6 tables. When creating the first 3 tables, everything works well. But then when I have to use a Foreign Key that I have used previously when creating another table, the system presents an error.
These are the 3 first tables:
CREATE TABLE Employee (
EmployeeID INTEGER PRIMARY KEY NOT NULL,
Name TEXT NOT NULL,
Position TEXT NOT NULL,
Salary REAL NOT NULL,
Remarks TEXT
);
CREATE TABLE Planet (
PlanetID INTEGER PRIMARY KEY NOT NULL,
Name TEXT NOT NULL,
Coordinates REAL NOT NULL
);
CREATE TABLE Has_Clearance (
Employee INTEGER NOT NULL
CONSTRAINT fk_Employee_EmployeeID REFERENCES Employee(EmployeeID),
Planet INTEGER NOT NULL
CONSTRAINT fk_Planet_PlanetID REFERENCES Planet(PlanetID),
Level INTEGER NOT NULL,
PRIMARY KEY(Employee, Planet)
);
Then I create the 4th table:
CREATE TABLE Shipment (
ShipmentID INTEGER PRIMARY KEY NOT NULL,
Date TEXT,
Manager INTEGER NOT NULL
CONSTRAINT fk_Employee_EmployeeID REFERENCES Employee(EmployeeID),
Planet INTEGER NOT NULL
CONSTRAINT fk_Planet_PlanetID REFERENCES Planet(PlanetID)
);
And I get the following error:
"There is already an object named 'fk_Employee_EmployeeID' in the database. Could not create constraint."
Please let me know how to create the FK in this 4th table.
The constraint "fk_Employee_EmployeeID" is first created on table "Has_Clearance" and then you try to create another constraint with the same name - which is not allowed.
Just rename the constraint in the 4-th table like this:
CREATE TABLE Shipment (
ShipmentID INTEGER PRIMARY KEY NOT NULL,
Date TEXT,
Manager INTEGER NOT NULL CONSTRAINT fk_Maneger_EmployeeID REFERENCES Employee(EmployeeID),
Planet INTEGER NOT NULL CONSTRAINT fk_Planet_PlanetID REFERENCES Planet(PlanetID)
);

SQL Unknown number of attributes

I have a one-to-many relationship between two classes for this situation. I have a swimming competition and that competition can have x swimmers.
How can I create an SQL table for this, I know I will have to use the Primary Key of Swimmers as a foreign key in the Swimming competition but I have no idea how to represent the correct number of attributes since it's unknown.
This is called a m:n relationship and usually solved with a mapping table.
Something like this:
create table swimmer
(
id integer not null primary key,
lastname varchar(100) not null,
firstname varchar(100)
)
create table competition
(
id integer not null primary key,
name varchar(50) not null,
comp_date date not null
)
create table participant
(
swimmer_id integer not null,
competition_id integer not null,
rank_in_competetion integer,
primary key (swimmer_id, competition_id),
constraint fk_participant_swimmer (swimmer_id) references swimmer(id),
constraint fk_participant_competition (competition_id) references competition(id)
)