Design SQL tables with a list behaviour - sql

I have one table
Client (
id SERIAL PRIMARY KEY );
Another table;
Exercise (
id SERIAL PRIMARY KEY );
And a final table;
Workout (
name VARCHAR,
creator INT REFERENCES Client(id),
exercise INT REFERENCES Exercise(id),
PRIMARY KEY(name,creator,exercise) );
My tables has some other columns aswell but these are all the relevant ones.
A workout has a creator, it is given a name (for example 'legs - monday' or whatever) and then it has a list of unique exercises one is to perform during this workout. So in an Object oriented approach this would look something like
Object Workout
string name
int creator
List<Exercise> exercises
So far this has worked well for me but now i need to create a new table that has a reference to a workout, and i am not sure how to capture this. Maybe my implementation of this is wrong?
table A (
id SERIAL PRIMARY KEY,
workout References Workout(?) );
I cannot reference (name,creator) since it is not marked as unique, and even if it was i would only be able to add one exercise then. It seems silly to reference all rows in Workout (my teacher in relational databases would skin me alive).
Would it be bad practice to just reference one arbitrary entry to a workout (name,creator,exercise)? If i have the name and the creator i can just make a select statement and get all the exercises from them. All rows where the tuple (name,creator) match are said to belong to the same workout.

Children should reference a parent, not vice versa:
create table client (
id serial primary key
);
create table workout (
id serial primary key,
name varchar,
creator int references client(id)
);
create table exercise (
id serial primary key,
workout int references workout(id)
);
Then your list view for a given workout may look like this:
select *
from workout w
left join exercise e on e.workout = w.id
where name = 'some name';
Edit. In case of many-to-many relationship the common way is to create so-called join table, e.g.:
create table workout_parts (
workout int references workout(id),
exercise int references exercise(id),
primary key (workout, exercise)
);

Related

SQL - How to save data with a key value

My question: is there a way to save data into a SQL database with a key value? I have an example below.
As you see in the example table below, in column Friends I have ""Uno", John". "Uno" would be the key value that is associated with "John".
I would be able to get the data from "Uno" like this:
SELECT *
FROM Table_Name
WHERE KEY VALUE = "Uno"
Is saving data like this possible? If not, I would love some suggestions!
Thank you!
Saving keys is not only possible, but it's also one of the fundamental abilities of relational databases. You don't want to store friends' names though, just store keys of them and make an SQL query to get names from keys.
This is a pseudocode you might use, but it might not compile for every DBMS
CREATE TABLE people (
id INT NOT NULL PRIMARY KEY,
name CHAR(30)
);
CREATE TABLE friends (
person_id INT NOT NULL PRIMARY KEY FOREIGN KEY REFERENCES people(id),
friend_id INT NOT NULL PRIMARY KEY FOREIGN KEY REFERENCES people(id)
);

Declaring a table in an inheritance hierarchy, where the children also references another entry in the base table

My problem, simplified and translated to something any programmer can relate to, looks like this:
I have an Issue Tickets table. Each entry (ticket) has a type: simple or complex. I use a numerical unique id as PK.
A complex ticket needs additional information compared to a simple ticket, so there's another table just for complex tickets. One of such info must reference a different ticket id. Imagine that this is because a complex ticket is linked to a pre-existing ticket issue from which it depends (always exactly only one and never its own!).
The Complex Ticket table uses as PK a FK: the Issue Tickets PK. Since the complex ticket always needs to specify another ticket id (constraints: not its own), I need to use another FK to Issue Tickets as a 'normal' field.
Can I do something of the sort? Is it a bad pattern?
CREATE TABLE Issue_Tickets
(
ticket_id INT AUTO_INCREMENT NOT NULL,
ticket_type CHAR(8) NOT NULL,
PRIMARY KEY (ticket_id)
)
CREATE TABLE Complex_Tickets
(
ticket_id INT NOT NULL,
father_ticket_id INT NOT NULL,
FOREIGN KEY (ticket_id) REFERENCES Issue_Tickets(ticket_id),
FOREIGN KEY (father_ticket_id) REFERENCES Issue_Tickets(ticket_id),
PRIMARY KEY (ticket_id)
CONSTRAINT no_self_reference CHECK (ticket_id <> father_ticket_id)
)

Creating foreign key in Visual Studio 2010

I'm trying to create 2 tables in Visual Studio server pane and I have a problem creating the foreign keys.
When I'm trying to create them in the relationship page it won't let me create foreign keys until I make them primary keys.
I don't understand why I can't have a different member in my table that it is primary key and a different one a foreign key.
My tables are like this:
Table People:
Primary key: ID int
Name nvarchar
Age int
City nvarchar
Foreign key: AccountNumber int --> when I make him primary key everything works.
Table BankAccount:
Primary key and Foreign Key: AccountNumber int
Money float
ps.
I used some mysql with CMD and I remember that I could do this, but because I don't have this control in visual studio I'm lost.
UPDATE:
Rup made a good point that i only relize afther answering the qustion he ask me
i just did the realtionship (Foreign Key) for the bank account table and now i got
what i wanted thank you!
Why is BankAccount.AccountNumber a Foreign Key? Are you trying to reference back to the the person who owns it?
If that is the case, BankAccount should be:
CREATE TABLE BankAccount
(
AccountNumber int PK,
Money float, // bad idea. Use currency or int (i.e. store balance as pennies)
Owner int FK REFERENCES People.ID
)
And drop the account ID from the people table.
This models the relationship "an Account has 1 and only one owner" and allows the relationship "A person can have many accounts."
It looks like what you're trying to do is create a back reference. If you were to choose to do this, then the back reference to the owner should be on People.ID, not on account. -- Although this is unnecessary because you can simply query
SELECT * FROM
BankAccount INNER JOIN People ON BankAccount.Owner = People.ID
to get all accounts and their owners.
If you want to establish multiple owners for an account, AND many accounts per user, then you need to establish a third table to implement the many-to-many relationship.
CREATE TABLE AccountOwners
(
AccOwnID int PK,
AccountID int FK REFERENCES BankAccount.AccountNumber,
PeopleID int FK REFERENCES People.ID
)
And drop the People.AccountNumber and BankAccount.Owner. This technique is akin to maintaining a list of all accounts and owners which you can query.

SQL One-to-Many Table vs. multiple one-to-one relationships

I'm working on a project with the following objective: A User can create a Challenge and select an optional Rival to take part of this challenge. The Challenge generates Daily entries and will track stats on these.
The basic User and Entry entities look like this:
CREATE TABLE users (
id (INT),
PRIMARY KEY (id)
);
CREATE TABLE entries (
challengeId INT,
userId INT,
entryDate DATE,
entryData VARCHAR,
PRIMARY KEY (challengeId, userId, entryDate)
)
The piece I'm having trouble with is the Challenge piece with the Rival concept. I can see two approaches.
// Hard code the concept of a Challenge Owner and Rival:
CREATE TABLE challenges (
id INT,
name VARCHAR,
ownerId INT,
rivalId INT NULL,
PRIMARY KEY (id),
UNIQUE KEY (ownerId, name)
);
// Create Many-to-one relationship.
CREATE TABLE challenges (
id INT,
name VARCHAR,
PRIMARY KEY (id),
UNIQUE KEY (name)
)
CREATE TABLE participant (
challengeId INT,
userId INT,
isOwner BIT,
PRIMARY KEY (challengeId, userId)
)
The problem with the first approach is that referential integrity is tough since now there are two columns where userIds reside (ownerId and rivalId). I'd have to create two tables for everything (owner_entries, rival_entries, owner_stats, etc.) in order to set up foreign keys.
The second approach solves this and has some advantages like allowing multiple rivals in the future. However, one thing I can't do anymore with that approach is enforce Challenge name uniqueness across a single user instead of the whole Challenge table. Additionally, tasks like finding a Challenge's owner is now trickier.
What's the right approach to the Challenges table? Is there anyway to set up these tables in a developer friendly manner or should I just jump all the way to Class Table Inheritance and manage the concept of Owner/Rivals there?
I think the way I would set this up is as follows (using the second approach):
CREATE TABLE challenges (id INT,
name VARCHAR,
owner_id INT,
PRIMARY KEY (id),
UNIQUE KEY (name, owner_id))
CREATE TABLE participant (challengeId INT,
userId INT,
PRIMARY KEY (challengeId, userId))
This allows easy tracking of who owns the challenge, yet extracts out the individual participants.
This would also allow you to unique the challenge name by the owner safely, and foreign keys on the userId in participant are easy. 'Rivals' are then all participants that are not the challenge owner.
I treat the first approach the right one.
You could have one table for users and one for challenges.
Are you aware that you can reference one table twice like below?
SELECT * FROM CHALLENGES
INNER JOIN USERS AS OWNERS ON OWNERS.ID = CHALLENGES.OWNERID
INNER JOIN USERS AS RIVALS ON RIVALS.ID = CHALLENGES.RIVALID
In this case you can reference both rivals and owners without creating new tables.

Need help understanding this SQL (generated by doctrine)

i am actually reading Doctrine Reference: One to Many, Unidirectional with Join table. but this will probably be more of a SQL quesiton. basically, this is supposed to model a one to many, unidirectional relationship. i guess from the PHP code (in that link), its such that 1 user have many phonenumbers.
the question is from the SQL, it seems like 1 user can have many phonenumbers. and 1 phonenumber can only belong to 1 user. am i right?
CREATE TABLE User (
id INT AUTO_INCREMENT NOT NULL,
PRIMARY KEY(id)
) ENGINE = InnoDB;
CREATE TABLE users_phonenumbers (
user_id INT NOT NULL,
phonenumber_id INT NOT NULL,
UNIQUE INDEX users_phonenumbers_phonenumber_id_uniq (phonenumber_id),
PRIMARY KEY(user_id,
phonenumber_id)
) ENGINE = InnoDB;
CREATE TABLE Phonenumber (
id INT AUTO_INCREMENT NOT NULL,
PRIMARY KEY(id)
) ENGINE = InnoDB;
ALTER TABLE users_phonenumbers ADD FOREIGN KEY (user_id) REFERENCES User(id);
ALTER TABLE users_phonenumbers ADD FOREIGN KEY (phonenumber_id) REFERENCES Phonenumber(id);
can't i just simplify the database to ... below ... no need for join tables and what not?
Users (id, name)
Phonenumbers (id, user [FK], number)
Correct, these are two valid approaches to the same problem. And yes, the unique index on users_phonenumbers means that each phone number can belong to only one user.
The design is actually suboptimal.
The idea must have been that there are telephone numbers, users, and that they can be linked many-to-many. Because of the unique index on phonenumberid hoever, each number can only be assigned to one user.
Then the whole users_phonenumbers has become redundant, because they could just have added a userid column on the phonenumbers table and save themselves a join.
BAd table design if you ask me.