i am very new to MySQL and making my first steps with it. I have right now 2 tables that look like this:
Event:
+-------+-------------+
| Field | Type |
+-------+-------------+
| id | int(11) |
| name | varchar(30) |
| date | datetime |
+-------+-------------+
User:
+----------+-------------+
| Field | Type |
+----------+-------------+
| name | varchar(30) |
| amount | int |
+----------+-------------+
Now i would like to be able to add an dynamic amount of Users to an Event but i am not sure how i should create an dynamic table for that or how otherwise i should implement such an behaviour. What would be the best practice?
Help would be appreciated.
That is a classic many-to-many relation. You handle it by adding a new table
event_users table
-----------------
event_id
user_id
For an event (id=1) having two users (id=3,4) it looks like this
event_id | user_id
1 | 3
1 | 4
To get all users of an event you would do this
select u.name
from users u
join event_users eu on eu.user_id = u.id
join events e on eu.event_id = e.id
where e.name = 'my event'
You need a third table, a junction table:
create table UserEvents (
UserEventId int auto_increment primary key,
UserId int,
EventId int,
constraint fk_userevents_userid foreign key (UserId) references Users(id),
constraint fk_userevents_eventid foreign key (EventId) references Events(id)
);
Notes:
I name tables in the plural.
The id for the table is the singular followed by "id" (so I prefer Users(UserId) and Events(EventId).
This has declared foreign key relationships.
If duplicates are not allowed, then you also want a unique constraint on (UserId, EventId).
For this you should use a third table in which you should maintain event and related user id.
user_event
id user_id event_id created_date
user_id and event_id are foreign keys for this table and will point primary keys of user and event table respectively
Related
I have a many-to-many table with UserId and TaskId
When I add data to the table I can add the same UserId and TaskId more than once.
I use the following query to add the data:
Create table if not exists user_task(UserId INT, FOREIGN KEY (UserId)
REFERENCES USERS(id), TaskId INT, FOREIGN KEY (TaskId) REFERENCES TASKS(id));
How can I prevent adding duplicates of those in the table?
+-----------------+
| UserId | TaskId |
+-----------------+
| 1 | 1 |
| 2 | 1 |
| 1 | 1 |
+---------+-------+
I know I can put DISTINCT in the SELECT query to get the data without duplicates but it doesn't prevent from being added to the table.
You can use Unique Index Constraint
Basically it will check for duplicates (upon one column or groups of columns) and stops insert/update operations if constraint would break.
If you're interested in how to deal with this, check out the manual
I'm thinking about having one image table to store images of any other independent table like user, product and so... (of course any single instances of independent tables (like John Smith as a user, and laptop as a product) may have 0, 1, or multiple images.
The image table has id, title and filename.
And I'm thinking an imagetable table to relate images to their proper image owners like user with these fields: image_id, table_id and table.
Some entries might look like this:
image_id | table_id | table
-----------------------------
1 | 1 | user
2 | 1 | user
3 | 2 | user
4 | 2 | user
5 | 1 | product
6 | 1 | product
7 | 1 | product
8 | 2 | product
9 | 3 | product
10 | 3 | product
11 | 4 | product
Now the question is:
Is this database design advised? What's the best approach to this request?
Of course the other way is to have user_image, product_image and company_image tables instead of a single image_table table.
No, because then you lose the advantage of foreign keys.
Use junction tables:
create table product (
product_id bigserial primary key,
name citext not null unique
);
create table user (
user_id bigserial primary key,
name citext not null unique
);
-- personally, I would store the file in the db and use incremental backups
-- pedantically, I prefer "picture" over "image" as "image" has 2 meanings in computers
create table picture (
picture_id bigserial primary key,
filename citext not null,
...
);
create table product_picture (
product_id bigint references product(product_id),
picture_id bigint references picture(picture_id),
primary key (product_id, picture_id)
);
create table user_picture (
user_id bigint references user(user_id),
picture_id bigint references picture(picture_id),
primary key (user_id, picture_id)
);
In general, we can use unique key or primary key to prevent this, but in my case. I am creating an MyFavorite table like this:
---------------------------------------------------------
| UserName | FavoriteLink |
---------------------------------------------------------
| Ryan | http://www.google.com |
---------------------------------------------------------
| Ryan | http://www.yahoo.com |
---------------------------------------------------------
| Joyce | http://www.google.com |
---------------------------------------------------------
| Joyce | http://www.cnn.com |
---------------------------------------------------------
So, each user can have a lot of favoritelinks, but they shouldn't have duplicate favoritelink, for example, Ryan shouldn't have two favoritelink for http://www.google.com. but for this table, FavoriteLink field may be duplicate, because both Ryan and Joyce, they all have favoritelink for http://www.google.com.
Here is the question: how can I insert data into this table without duplicate FavoriteLink for specific person?
Composite keys.
CREATE TABLE userlinks (
user VARCHAR(255),
link VARCHAR(255),
PRIMARY KEY (user, link)
)
or
CREATE TABLE userlinks (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
user VARCHAR(255),
link VARCHAR(255),
UNIQUE KEY (user, link)
)
depending on what exactly it is you want.
You can add a composite unique index.
CREATE UNIQUE INDEX username_favorite_uniq ON yourTable (UserName, FavoriteLink)
I have this database where I have stored some tags in it.
I stored the tags like this:
"humor,funny,animal"
Now I need a mysql query that selects this line when I search for "humor", "funny" or "animal". What I have until now:
SELECT id FROM database WHERE tags REGEXP 'humor' LIMIT 1
Unfortunately, it does not work. Could someone of you please help me out?
Edit: Thanks for all the responses! I will now need to study this first! But problem solved :)
Short Term
Because the tags are stored as denormalized data, use the FIND_IN_SET function:
SELECT t.id
FROM YOUR_TABLE t
WHERE FIND_IN_SET('humour', t.tags) > 0
Long Term Solution
Setup the tables to properly handle a many-to-many relationship:
TAGS
tag_id (primary key)
tag_description
ITEMS
item_id (primary key)
ITEM_TAGS
item_id (primary key, foreign key to ITEMS.item_id)
tag_id (primary key, foreign key to TAGS.tag_id)
Making the two columns in ITEM_TAGS the primary key means you don't have to worry about duplicates. And yes, this means using the InnoDB engine...
Then, you can use:
SELECT i.item_id
FROM ITEMS i
WHERE EXISTS (SELECT NULL
FROM ITEM_TAGS it
JOIN TAGS t ON t.tag_id = it.tag_id
WHERE t.tag_description = 'humour'
AND it.item_id = i.item_id)
You can use LIKE
SELECT id FROM database WHERE tags LIKE '%humor%' LIMIT 1
Which will search for any entry where 'humor' is a substring. Note this will also return items tagged 'humorous'.
But like others said, having a separate table for tags would be best. To do this you will also need a pivot table.
So for example
-------------- data -------------
| ID | NAME |
| 1 | example |
| 2 | example 2 |
-----------------------------------
-------------- tags -------------
| ID | NAME |
| 1 | humor |
| 2 | cats |
| 3 | wumpus |
-----------------------------------
------------ data_tags ----------
| DATA_ID | TAG_ID |
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 3 |
-----------------------------------
To expand on Tomalak's comment, this would be best solved using a many-to-many relationship for database to tag relationships. This involves adding two new tables. Something like this (forgive my rusty MySQL)
CREATE TABLE `Tag` (
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
tag VARCHAR(64) NOT NULL,
PRIMARY KEY (id),
UNIQUE (tag)
) ENGINE=InnoDB;
CREATE TABLE `DatabaseTag` (
database_id INT(11) UNSIGNED NOT NULL, -- just guessing your database.id type here
tag_id INT(11) UNSIGNED NOT NULL,
PRIMARY KEY (database_id, tag_id),
FOREIGN KEY (database_id) REFERENCES `database` (id)
ON DELETE CASCADE,
FOREIGN KEY (tag_id) REFERENCES `Tag` (id)
ON DELETE CASCADE
) ENGINE=InndoDB;
Then, to find all the database records matching tag "humour", your query would look like
SELECT id FROM `database` d
INNER JOIN `DatabaseTag` dt ON d.id = dt.database_id
INNER JOIN `Tag` t ON dt.tag_id = t.id
WHERE t.tag = 'humour'
I have two tables like:
-- users
+----+--------+---------------------+----------+--------------------+
| id | name | email | password | cookie |
+----+--------+---------------------+----------+--------------------+
-- user_detail
+---------+-----+-------------------+----------------+
| user_id | age | about | birthday |
+---------+-----+-------------------+----------------+
I need to make a relation between users(id) and user_detail(user_id) columns. Now I want to know, should I open user_detail table and create a relation on the user_id column of it (which refers to users(id)) or vice versa?
You are looking for syntax like this:
alter table user_details add constraint fk_user_details_user_id
foreign key (user_id) references users(id);