Adding an Array of INT column where each value is a primary key from another table - sql

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';

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
);

multiple foreign keys as primary key postgres, should I do it?

This is one of those: why I should or why I should not.
So my books app has reviews, but one user must not review the same book more than one time. In my point of view makes sense to create a table for the reviews and make the user_id and the book_id (ISBN) as the PRIMARY KEY for the reviews table. But, could it be a problem at some point if the application gets too many reviews, for example, could that decision slow the queries?
I am using postgres and I am not sure if the following code is correct:
CREATE TABLE users(
user_id PRIMARY KEY SERIAL,
user_name VARCHAR NOT NULL UNIQUE,
pass_hash VARCHAR NOT NULL,
email VARCHAR NOT NULL UNIQUE,
);
CREATE TABLE books(
book_id PRIMARY KEY BIGINT,
author VARCHAR NOT NULL,
title VARCHAR NOT NULL,
year INT NOT NULL CHECK (year > 1484),
review_count INT DEFAULT 0 NOT NULL,
avrg_score FLOAT,
);
CREATE TABLE reviews(
user_id INT FOREIGN KEY REFERENCES users(user_id) NOT NULL
book_id INT FOREIGN KEY REFERENCES books(book_id) NOT NULL
score INT NOT NULL CHECK (score > 0, score < 11)
PRIMARY KEY (book_id, user_id)
);
This is a perfectly valid design choice.
You have a many-to-many relationship between books and users, which is represented by the reviews table. Having a compound primary key based on two foreign keys lets you enforce referential integrity (a given tuple may only appear once), and at the same time provide a primary key for the table.
Another option would be to have a surrogate primary key for the bridge table. This could make things easier if you need to reference the reviews from another table, but you would still need a unique constraint on both foreign key columns for integrity, so this would actually result in extra space being used.
When it comes to your code, it has a few issues:
the primary key keyword goes after the datatype
the check constraint is incorrectly formed
missing or additional commas here and there
Consider:
CREATE TABLE users(
user_id SERIAL PRIMARY KEY ,
user_name VARCHAR NOT NULL UNIQUE,
pass_hash VARCHAR NOT NULL,
email VARCHAR NOT NULL UNIQUE
);
CREATE TABLE books(
book_id BIGINT PRIMARY KEY,
author VARCHAR NOT NULL,
title VARCHAR NOT NULL,
year INT NOT NULL CHECK (year > 1484),
review_count INT DEFAULT 0 NOT NULL,
avrg_score FLOAT
);
CREATE TABLE reviews(
user_id INT REFERENCES users(user_id) NOT NULL,
book_id INT REFERENCES books(book_id) NOT NULL,
score INT NOT NULL CHECK (score > 0 and score < 11),
PRIMARY KEY (book_id, user_id)
);
I the above is good but I would drop columns review_count and avrg_score from books. These are derivable when needed. If needed for your application then instead of storing these create a view to derive them. This avoids the always complicated process of maintaining running values:
create view books_vw as
select b.book_id
, b.author
, b.title
, b.year
, count(r.*) review_count
, avg(r.score) avrg_score
from books b
left join reviews r
on r.book_id = b.book_id
group by
b.book_id
, b.author
, b.title
, b.year
;

Determine table structure

I want to create db for anime. This is my ER structure:
https://ibb.co/ctRk8f6
Any tips to improve this?
Every anime has blob for image and relations to brand and episode, each episode may have multiple links and relation to tag.
I wanted to know if this structure is good or should I make separate table for image or any other tip
CREATE TABLE Brand
(
id INT NOT NULL,
name INT NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE Tag
(
id INT NOT NULL,
name INT NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE Anime
(
id INT NOT NULL,
name INT NOT NULL,
img INT NOT NULL,
id INT,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES Brand(id)
);
CREATE TABLE Episode
(
order INT NOT NULL,
rating INT NOT NULL,
date INT NOT NULL,
id INT NOT NULL,
PRIMARY KEY (order, id),
FOREIGN KEY (id) REFERENCES Anime(id)
);
CREATE TABLE Link
(
link INT NOT NULL,
host INT NOT NULL,
order INT NOT NULL,
id INT NOT NULL,
PRIMARY KEY (link, order, id),
FOREIGN KEY (order, id) REFERENCES Episode(order, id)
);
CREATE TABLE TagOfAnime
(
id INT NOT NULL,
id INT NOT NULL,
PRIMARY KEY (id, id),
FOREIGN KEY (id) REFERENCES Anime(id),
FOREIGN KEY (id) REFERENCES Tag(id)
);
A few issues here:
Why is everything of type INT? I would assume that name would be a nvarchar of some maximum length nvarchar(200) perhaps?
Your TagOfAnime table has two columns named id. That will not work. If they are references to the primary keys to the tag and Anime tables, then you should name them as such: Tag_id and Anime_id
I would not name a table Link. What is it "linking"? I would make it more descriptive.
In general, add a table if there can be multiple items associated with a single row in another table - as you are doing with the tags for Animes. Otherwise, if the data can appear in additional columns of a single row of the base table, then consolidate your tables to avoid complexity.
Other than that, ask specific questions where you are stuck and I'm sure someone will jump in to help.

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)
)