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
);
Related
Given two tables like so
CREATE TABLE participants(
id SERIAL PRIMARY KEY,
Name TEXT NOT NULL,
Title TEXT NOT NULL
);
CREATE TABLE meetings (
id SERIAL PRIMARY KEY,
Organizer TEXT NOT NULL,
StartTime DATE NOT NULL,
EndTime DATE NOT NULL,
Participants INT[],
);
I want Participants column of 'meetings' table to contain set of integers which are all primary keys (specific participant) from 'participants' table.
How do I define this field in 'meetings' table ?
The old fashioned way is to create a many-many table, with a couple of commonsense constraints:
CREATE TABLE meetings_participants(
meeting_id int not null,
participant_id int not null,
primary key (meeting_id, participant_id),
foreign key(meeting_id) references meetings(id),
foreign key(participant_id) references participants(id)
)
Now it is easy to add and remove people to meetings be inserting or deleting rows or query meetings that e.g. have 4 or more participants.
A more common approach is to create a junction table for the meeting participants.
CREATE TABLE participants (
participant_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
Name TEXT NOT NULL,
Title TEXT NOT NULL
);
CREATE TABLE meetings (
meeting_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
Organizer TEXT NOT NULL,
StartTime DATE NOT NULL,
EndTime DATE NOT NULL
);
CREATE TABLE meeting_participants(
meeting_id INT NOT NULL,
participant_id INT NOT NULL,
PRIMARY KEY (meeting_id, participant_id),
FOREIGN KEY (meeting_id) REFERENCES meetings(meeting_id),
FOREIGN KEY (participant_id) REFERENCES participants(participant_id)
);
Which is then used to join the 2 tables.
For example:
SELECT m.*, p.*
FROM meeting_participants mp
JOIN meetings m USING(meeting_id)
JOIN participants p USING(participant_id)
WHERE m.Organizer = 'John Doe';
I have 2 tables and I am trying to create a Foreign Key between the two. Here is the structure of my tables:
create table users (
id serial,
user_name varchar(50)
);
create table playlists (
id serial,
user_id integer references users(id)
);
I keep getting this error:
ERROR: there is no unique constraint matching given keys for referenced table "users"
Why is there not a unique constraint? If I create the id in the users table as integer PRIMARY KEY, then everything works fine. How do I fix this where the users id auto increments and can be the FK in the playlists table?
Creating a column of type serial doesn't make it the primary key or constraint it in any way. serial just creates an integer column, creates a sequence, and attaches the sequence to the column to provide default values. From the fine manual:
In the current implementation, specifying:
CREATE TABLE tablename (
colname SERIAL
);
is equivalent to specifying:
CREATE SEQUENCE tablename_colname_seq;
CREATE TABLE tablename (
colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;
If you want your id serial columns to be primary keys (which you almost certainly do), then say so:
create table users (
id serial not null primary key,
user_name varchar(50)
);
create table playlists (
id serial not null primary key,
user_id integer references users(id)
);
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.
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)
)
Below are two schema which I believe achieve the same result, i.e. m:n relationship with the option for a default/preferred value. Is there any reason to use one over the other?
Schema #1
CREATE TABLE people (
id serial,
primary key (id)
);
CREATE TABLE names (
id serial,
first_name text not null,
last_name text not null,
primary key (id)
);
CREATE TABLE person_has_name (
person_id integer not null references people (id),
name_id integer not null references names (id),
is_default boolean not null default false,
primary key (person_id, name_id)
);
Schema #2
CREATE TABLE people (
id serial,
default_name_id integer references names (id),
primary key (id)
);
-- this table has not changed
CREATE TABLE names (
id serial,
first_name text not null,
last_name text not null,
primary key (id)
);
CREATE TABLE person_has_name (
person_id integer not null references people (id),
name_id integer not null references names (id),
primary key (person_id, name_id)
);
Let's analyze:
Second schema prevent to you to set more than one name as default, but don't prevent to you to set as default name some not related name.
Opposite happens with first schema.
I propose to you (to your zombie user) a third schema that solves math problems:
CREATE TABLE people (
id serial,
default_name_id integer ,
primary key (id),
constraint default_person_name_fk --<--HERE
foreign key (id, default_name_id)
references person_has_name (person_id, name_id)
);
-- this table has not changed
CREATE TABLE names (
id serial,
first_name text not null,
last_name text not null,
primary key (id)
);
CREATE TABLE person_has_name (
person_id integer not null references people (id),
name_id integer not null references names (id),
primary key (person_id, name_id)
);
Regards and sorry about delay, I'm lag ;)
With the second schema you can't add people without first knowing their name. As long as this is ok (i.e. you know that whenever a person is added, they have to reveal their name), then I'd say that either of these schemas are fine, and that schema #2 might even be more optimized in the scenario where you need to query only for the default name.
I would use none of the two.
Solution 1 does not prevent you from having 2 default names for a person.
Solution 2 does not prevent a person having a default name that is not his. You could change the Foreign Key from default_name_id references names(id) to (person_id, default_name_id) references person_has_name(person_id, name_id) but then you'd have circular references and that's another problem, hard to solve.
You could use this, similar to your 2nd solution:
CREATE TABLE people (
id serial,
--- no default_name_id as foreign key here
primary key (id)
);
CREATE TABLE names (
id serial,
first_name text not null,
last_name text not null,
primary key (id)
);
CREATE TABLE person_has_name (
person_id integer not null references people (id),
name_id integer not null references names (id),
primary key (person_id, name_id)
);
With this extra table, for those persons that have a default name:
CREATE TABLE person_default_name (
person_id integer not null,
name_id integer not null,
primary key (person_id),
foreign key (person_id, name_id)
references person_has_name (person_id, name_id)
);