Using databases and tables (MySQL) - mysql

On my website, customers have the option of creating an event with various items (that have attributes like seller, color, etc.).
Should I have ONE database and a new table for each event? I don't know of another way to program this and splitting every customer/event into a new database seems like a bad solution, but I'm new to databases and don't know if that's stupid.
I assume that I'd have a TABLE with user IDs, a TABLE for each event, and a TABLE that links the user to the event(s) he/she created. Is this the optimal way to do this? All in one database?
Thanks!

You should have a one-to-many relationship between a user table, and an event table. The event table should have the user ID as a foreign key.
CREATE TABLE user (
id int UNSIGNED AUTO_INCREMENT NOT NULL,
name varchar(50) NOT NULL,
last_modified timestamp NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY (name)
);
CREATE TABLE event (
id int UNSIGNED AUTO_INCREMENT NOT NULL,
user_id int UNSIGNED NOT NULL,
name varchar(50) NOT NULL,
description varchar(500) NOT NULL,
last_modified timestamp NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES user.id ON UPDATE CASCADE ON DELETE CASCADE
);
So then, you have your users, and when you add an event, you just assign the user_id to whatever user the event is for. Hopefully that gives you something to build from.

If you have a small number of event types, and the event types are very different in nature (different properties) then you may create a different table for each event type.
However usually you will create one database with one table for all the events, with a column for event type or code (if needed). You also don't need to create a table that contain all the event types, your code can contain them. You table should contain only the actual events that were fired.

Related

New with databases, having problems wiith primary key

I have a table where events organized by a sports center are stored.
I created it like this:
create table events(
name varchar(20) primary key,
description varchar(150),
type varchar(20) not null,
event_date not null,
event_start time not null,
event_end time not null,
room_name varchar(20) not null,
foreign key(room_name) references rooms(name) on update cascade on delete cascade);
now I have realized that events with the same name can exist as long as they are not on the same day.
For example, a swimming competition can be held several times in a month and still have the same name. How can I modify the table so that the primary key is made up of name and date without having to delete and re-create the table?
You could use an alter table statement to drop the primary key and add a new one:
ALTER TABLE events DROP PRIMARY KEY;
ALTER TABLE events ADD PRIMARY KEY (name, event_date);
It's worth reading up about primary keys.
As #mureinik says, you can drop the original key and create a new key - but your design has a few problems.
Firstly, primary keys should never change. Columns like "Name" suggest they can change - even if the user corrects a typo, or if the event changes its name (e.g. to add a sponsor). This goes for "room" too.
Secondly, your design combines two logical entities into a single table. I think you have an entity called event_type (tennis tournament), and an event instance (1 July 2021). I think there will be more attributes of event type, which you won't want to copy for each instance (e.g. "description").
So, I think your schema is more like
event_type
----------
event_id int pk
event_name varchar
event_type varchar
event_description varchar
event_instance
--------------
event_type_id int fk pk
event_date date pk
event_start time not null,
event_end time not null,
room_id int fk

MySQL foreign key constraints : on updating one table, fill another table with some data from the first table

I have two tables, users table and login table.
Say:
Create table users(
id int not null,
name varchar not null,
email varchar not null,
password varchar not null,
entries int default 0,
primary key(id));
Create table login(
id int not null,
email varchar not null,
password varchar not null,
user_id int not null,
Primary key(id)),
Foreign key (user_id) references users(id));
What constraints can I add or how can i work my way around such that whenever i add a user in the users table, the email and password columns are added into the login table too (just like to say i create a minimized version of the users table which only contains login credentials of users). And whenever i delete a user from the users table, he should be removed from the login table.
I hope i have been descriptive enough😊
You can define constraint with cascade delete. To implement the update of dependent tables you need triggers. It is possible to define AFTER INSERT trigger where you can update any dependent tables.
At the same time, I would reconsider having redundant fields in the dependent table when you always can obtain it by joining with the main table.

Log user updates

In the making of a small community networking site, but I was seeking some advice as to how best to design a table that will store data to be pulled as a stream that shows for example:
User X has added a friend!
User Y has commented on a post!
User X changed their profile picture!
User X has changed their motto!
Currently this is my setup but before I continue wanted to know if I was on the right track
update_id int PK
member_id int FK
friend_id int FK
update_action text
update_time datetime
update_hidden tinyint
At the moment I was planning to run an extra insert query to update this table with each activity when a user does it, not sure if that is the best or in my case a good way to get this done. Any tips or advice will be appreciated thanks for your time.
You can have a table for all the different activities that your system should offer.
CREATE TABLE activity
(
id MEDIUMINT UNSIGNED PRIMARY KEY UNIQUE NOT NULL AUTO_INCREMENT,
description NVARCHAR(126) UNIQUE NOT NULL
);
For example: has commented on a post, has a new friend, etc.
And then log all the activities that happen, depending on the id of the activity (so that you can manually define where in the code which activity should be used) and store it somehow like this:
CREATE TABLE activityLog
(
id MEDIUMINT UNSIGNED PRIMARY KEY UNIQUE NOT NULL AUTO_INCREMENT,
userId UNSIGNED NOT NULL,
friendId UNSIGNED DEFAULT NULL,
acitivityId UNSIGNED NOT NULL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
hidden TINYINT(1) DEFAULT 0,
FOREIGN KEY(userId) REFERENCES users(id),
FOREIGN KEY(friendId) REFERENCES users(id),
FOREIGN KEY(acitivityId) REFERENCES activity(id)
);
Assuming that you have your users stored in a table called 'users'.
Just make sure that It's easy to create new activities, easy to link the events, etc.

mysql - referencing one foreign key to multiple possible primary keys

I'd like to set up the following database scenario:
CREATE TABLE IF NOT EXISTS `points` (
`po_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`po_north` INT,
`po_east` INT,
PRIMARY KEY (`po_id`),
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `lines`(
`li_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`li_from` INT NOT NULL,
`li_to` INT NOT NULL,
PRIMARY KEY (`li_id`),
FOREIGN KEY (`li_from`) REFERENCES points(`po_id`),
FOREIGN KEY (`li_to`) REFERENCES points(`po_id`),
) ENGINE=InnoDB;
Now I want to set up a third table, that sores some metadata like who created or altered a point or a line:
CREATE TABLE IF NOT EXISTS `metadata` (
`me_type` ENUM('point','line') NOT NULL,
`me_type_id` INT UNSIGNED NOT NULL,
`me_permissions` VARCHAR(255) NOT NULL,
`me_created_by` INT UNSIGNED NOT NULL,
`me_created_on` DATETIME NOT NULL,
`me_last_modified_by` INT UNSIGNED NOT NULL,
`me_last_modified_by` DATETIME NOT NULL,
) ENGINE=InnoDB;
My first approach was to set an ENUM with two types (points and lines). But the problem is still, that I cannot properly reference a foreign key to one of the tables. Is there any recommended solution for such problem in MySQL?
BTW:
The fields for me_created_by and me_last_modified_by shall reference to a table storing some user data.
Your case appears to be yet another instance of the design pattern known as "generalization specialization" or perhaps "table design for class inheritance".
If you think of points and lines as classes of objects, they are both subclasses of some more general class of objects. I'm not sure what name to give the superclass in this case. Here's one of several previous questions that address the same issue.
Extending classes in the database
Fowler gives an extensive treatment of the subject. Your case has an added wrinkle, because you are dealing with metadata. But that need not alter the design. You need a third table, which I'll call "Items" for lack of a better term. The key, "it_id" would be assigned an auto number, and you would add an item every time you add either a point or a line. The two columns "po_id" and "li_id" would not be assigned an auto number. Instead they would be foreign keys, referencing "it_id" in the Items table.
The references to points or lines in the metadata table would then be references to "items" and you could use that information to find information about points or lines as the case may be.
How helpful this is depends on what you are trying to do with the metadata.
Your tables points and lines should contain a foreign key to metadata – not the other way around. Doing so will save you from defining any more complicated table setups. Using this approach, a single metadata-entry could be re-used several times for many different points or lines. This isn't even MySQL specific but a general, normalized database structure.
you can do this using a trigger, you need to trigger an event that can create reference key for either point or line before you insert a record based on respective tables

How do you create a constraint on parent tables that also constrains the child tables?

I am not sure how to phrase the question so I'll illustrate the tables and the explain what I want to achieve.
-- static table of the entity classes supported by the application
create table entity_type (
id integer not null auto_increment,
name varchar(30) not null,
primary key(id)
);
-- static table of statuses supported by the application
create table entity_status (
id integer not null auto_increment,
name varchar(30) not null,
primary key(id)
);
-- table of valid combinations
create table entity_type_entity_status_link (
entity_type_id integer not null,
entity_status_id integer not null,
unique key(entity_type_id, entity_status_id),
foreign key(entity_type_id) references entity_type(id),
foreign key(entity_status_id) references entity_status(id),
);
-- The tables where user types and statuses are defined
create table user_type (
id integer not null auto_increment,
name varchar(30) not null,
entity_type_id integer not null,
primary key(id),
foreign key(entity_type_id) references entity_type(id)
);
create table user_status (
id integer not null auto_increment,
name varchar(30) not null,
entity_status_id integer not null,
primary key(id),
foreign key(entity_status_id) references entity_status(id)
);
-- table of valid pairs
create table user_type_user_status_link (
user_type_id integer not null,
user_status_id integer not null,
unique key(user_type_id, user_status_id),
foreign key(user_type_id) references user_type(id),
foreign key(user_status_id) references user_status(id),
);
The basic premise behind these tables is that the system supports core types and statuses and the user is able to create their own user types and statues that derive from these.
The question I have is that I cannot see a way of creating any database constraints on the user_type_user_status_link table to ensure that the you cannot insert a file_type - file_status pair where the parent entity_type - entity_status is itself not valid. Or is this something that would have to be done with triggers.
The basic premise behind these tables is that the system supports core
types and statuses and the user is able to create their own user types
and statues that derive from these.
Although that sounds like a laudable goal on the surface, the effect is to delegate database design to your users. Database design, because the effect of your desire to set foreign key references to a subset of the rows in entity_type_entity_status_link means each of those subsets is a defacto, unnamed table.
This approach never ends well.
What you've developed is the "One True Lookup Table". Google that for a host of reasons why OTLT is an anti-pattern.
The best solution is to model real things in your tables. (Entity isn't a real thing. It's an abstraction of a real thing.) Something along the lines of either
create table file_status (
file_status varchar(30) primary key
);
or
create table file_status (
file_status_id integer primary key,
file_status varchar(30) not null unique
);
would work well for file statuses.
In the case of the second one, you can set a foreign key reference to either the id number (saves space, requires an additional join) or to the status text (takes more space, eliminates a join). Note that you need the unique constraint on the status text; your original design allows the user to enter the same text multiple times. (You could end up with 30 rows where entity_type.name is 'File'.
You should use triggers for that.
MySQL does not support constraints of the form that will prevent what you want.