I want to the best schema to store reactions - mysql

i want to get different like reactions from user (like,heart,clapping,etc) for a post how i store in database
My Post Table is like below
| ID | TITLE | SLUG | CONTENT | COMMENTS_COUNT

Your best solution is likely to be a separate table, called something like post_reactions. That table would contain user_id, post_id, and type columns. This allows the use of things like COUNT, JOIN and GROUP BY to get the data sliced-and-diced up as needed.

Related

Mysql table relations

I have read various topics regarding table relations and while i am building my database i am a bit confused on what should i do.
I have 3 type of registration on my site(artist, fan, companies). Each registered user gets a unique key and username and the appropriate type of user (ex. fan). I am trying to involve music genres to all types of registration but genres will also be added to uploaded music files. At the moment i am storing one music genre per track and user by an array list that is shown in a form. Then system is storing it to the appropriate field. But i want some users to have more than 1 genres stored.
Now what i have done is below:
Users table (total 14 columns)
ID | username | email | password | type | signup | lastlogin | etc.
Settings table (total 10 columns)
ID | username | description | banner | country | genres | avatar etc.
Music table
ID | username | artist | title | maingenre | othergenre | cover | fileurl
By having in mind performance and let's assume that thousand of thousand users is registering...
Should i just add all settings column in the users table or it's ok to keep as i have them now? Settings can be updated by user while users table is updated by the system.
Should i split the user table according to users type? For example Artist table, fan table etc. that will store the appropriate registration and settings? Type of user needs to be in a column as is important for some functions of the site.
Regarding music table i was thinking to making a table for each genre that will store the uploads according to the genre specified by the user. Is this a good way of storing tracks to database or not? So when i want to call tracks of disco music i just use the disco music table.
Any help will be much appreciated.
not quiet sure I understand everything completely how your table is correlated, or what exactly you want or plan to do, but here is one idea about how to store genres in your database. And to connect it with your Setting table
First create table Genres in which you will store all genres. That table could look like this
Table: Genres
ID | genres_name | description etc.
ID - will be primary key auto increment
genres_name - will hold the name of genre (blues, jazz, disco...)
description - this column i added just if you want to add something specific by every genre it's not necessary
Next step is to create table Settings_genres. This table will store relation between your Setting table and Genres table and will look like this
Table: Settings_genres
settings_id | genres_id
So data in this table will look like this (for the setting ID 1 which will have 3 different Genres)
settings_id | genres_id
------------------------
1 | 2
------------------------
1 | 4
------------------------
1 | 5
------------------------
settings_id and genres_id will be primary key pair which means that you wont be able to store two identical pair int this table (You can have only one relation between one settings column and one genre column)
That is something called Many to many relationship and I'm sure that you can easily find more about that if you google it just a little.
When you want to pull data off from database which will show all settings and all genres you can do it with query like this
SELECT Settings.*, Genres.genres_name, Genres.description
FROM Settings
INNER JOIN Settings_Genres
ON Settings.ID = Settings_Genres.settings_id
INNER JOIN Genres
ON Settings_Genres.genres_id = Genres.ID
ORDER BY ID
Here is SQL Fiddle to see how it's look like.
When you want to pull data from settings table where that table is connected with specific genre you do that like this
SELECT Settings.*, Genres.genres_name, Genres.description
FROM Settings
INNER JOIN Settings_Genres
ON Settings.ID = Settings_Genres.settings_id
INNER JOIN Genres
ON Settings_Genres.genres_id = Genres.ID
WHERE Genres.genres_name = 'Rock'
ORDER BY ID;
This can also be achieved by this query which may be a little faster but let's not go into detail...
SELECT Settings.*, Genres.genres_name, Genres.description
FROM Settings
INNER JOIN Settings_Genres
ON Settings.ID = Settings_Genres.settings_id
INNER JOIN Genres
ON Settings_Genres.genres_id = Genres.ID
AND Genres.genres_name = 'Rock'
ORDER BY ID;
Here is FIDDLE for that...
So basically I suggest you to learn a little bit about relation between tables especially many to many relationship. And on than you will see how to improve your data table design.
Hope I help a little.
GL!
i think the way your table is, is okay. you dont have to split the table based on the type of users you have. but i think what you could use is font end technologies to allow users preform activities you want them, which is restricting them to only what you want them to do, they by controlling flow of information within the system. i hope that helps.

Avoiding JOIN to increase performance?

Lets say I have users table:
| id | username | email | address |
And posts table:
| id | post | user_id | date |
When I want to show posts, each time I need to go users table to retrieve username from user_id. I want to avoid using JOIN for this simple data retreive so what I do is adding another coloumn to posts table:
| id | post | user_id | username | date |
This way I will not have to use JOIN to retreive username when showing posts
Do you think that this is better?
no. your alternative structure is vulnerable to inconsistencies (e.g. if a user changes his name; read about 3rd Normal form here http://en.wikipedia.org/wiki/Third_normal_form#.22Nothing_but_the_key.22)
why don't you want to use JOINs? have you set up approriate indexes?
I think it depends on the design and future, niy I will suggest you not to do that:
although from present respect, you will think it will be better performance to avoid join, but what if your application expand, and it is no good to use this unnormalized table structure.
For instance, if one of the poster changed username, how could you achieve that? to update the whole table? if your data could exccess 10Million tuples, it will be tough because update will lock the table in the process of updating.
thus I will not recommend this.
Join performance can be omit if your application needs frequently updating in that way.
If the [id] of [users] table is the primary key, I think it is good enough to use JOIN.
Alternatively, if you select limited number of posts, such as 10 posts, can also try this sql:
select id, post, user_id,
(select username from users where id = user_id) as username, date
from posts
limit 0, 10

MySQL Display Table Name Along With Columns

I'm currently debugging a huge MySql call which joins a large amount of tables which share column names such as id, created_at, etc. I started picking it apart but I was wondering if there was a way to do something like:
SELECT * AS table.column_name FROM table1 LEFT JOIN etc etc etc...
In place of having to individually name columns like:
SELECT table1.`column2' AS 'NAME', table1.`column3` AS ...
It would definitely help with speeding up the debugging process if there's a way to do it.
Thanks.
Edit:
Thanks for the answers so far. They're not quite what i'm looking for and I think my question was a bit vague so i'll give an example:
Suppose you have this setup in your MySql Schema:
table: students
fields: INT id | INT school_id | VARCHAR name
table: schools
fields: INT id | INT name
students contains:
1 | 1 | "John Doe"
schools contains:
1 | "Imaginary School One"
Doing the MySql call "SELECT * FROM students LEFT JOIN schools ON (students.school_id = schools.id)" will yield:
id | school_id | name | id | name
1 | 1 | "John Doe" | 1 | "Imaginary School One"
We know better and we know that the first Id and Name columns refer to the students table and the second Id and Name refer to the schools table since the data set is really small and unambiguous with its naming. However, if we had to deal with a result set that contained multiple left joins and columns with similar names, then it would start to get difficult to read and normally you'd have to trace through it by following the joins. We could start doing something like
SELECT school.name AS 'school_name', etc etc etc...
But that gets incredibly impractical once you start dealing with large data sets.
I was wondering though if there was a way to return the result set wherein the column names would look like this instead:
students.id | students.school_id | students.name | schools.id | schools.name
Which would be useful for future references if I need to do something similar again.
What if you select the tables in order, and add a spacer column with the name.
i.e.
select 'table1', t1.*, 'table2', t2.*, 'table3', t3.*
...
At least that way you don't have to name specific columns.
you mean something like?
show tables;
desc <tablename>;
If you want to also return table names along with column names, you can use the CONCAT function.
EXAMPLE:
SELECT CONCAT('tableName', field) FROM tableNAme
Let us know if this is what you are looking for.
Why not use the same dot notation instead of the ambiguous underscores for separating your tables from column names. Just enclose the alias in back-ticks. For example:
SELECT students.id `students.id` FROM students;

Table with a lot of attributes

I'm planing to build some database project.
One of the tables have a lot of attributes.
My question is: What is better, to divide the the class into 2 separate tables or put all of them into one table. below is an example
create table User { id, name, surname,... show_name, show_photos, ...)
or
create table User { id, name, surname,... )
create table UserPrivacy {usr_id, show_name, show_photos, ...)
The performance i suppose is similar due to i can use index.
It's best to put all the attributes in the same table.
If you start storing attribute names in a table, you're storing meta data in your database, which breaks first normal form.
Besides, keeping them all in the same table simplifies your queries.
Would you rather have:
SELECT show_photos FROM User WHERE user_id = 1
Or
SELECT up.show_photos FROM User u
LEFT JOIN UserPrivacy up USING(user_id)
WHERE u.user_id = 1
Joins are okay, but keep them for associating separate entities and 1->N relationships.
There is a limit to the number of columns, and only if you think you might hit that limit would you do anything else.
There are legitimate reasons for storing name value pairs in a separate table, but fear of adding columns isn't one of them. For example, creating a name value table might, in some circumstances, make it easier for you to query a list of attributes. However, most database engines, including PDO in PHP include reflection methods whereby you can easily get a list of columns for a table (attributes for an entity).
Also, please note that your id field on User should be user_id, not just id, unless you're using Ruby, which forces just id. 'user_id' is preferred because with just id, your joins look like this:
ON u.id = up.user_id
Which seems odd, and the preferred way is this:
ON u.user_id = up.user_id
or more simply:
USING(user_id)
Don't be afraid to 'add yet another attribute'. It's normal, and it's okay.
I'd say the 2 separate tables especially if you are using ORM. In most cases its best to have each table correspond to a particular object and have its field or "attributes" be things that are required to describe that object.
You don't need 'show_photos' to describe a User but you do need it to describe UserPrivacy.
You should consider splitting the table if all of the privacy attributes are nullable and will most probably have values of NULL.
This will help you to keep the main table smaller.
If the privacy attributes will mostly be filled, there is no point in splitting the table, as it will require extra JOINs to fetch the data.
Since this appears to be a one to one relationship, I would normally keep it all in one table unless:
You would be near the limit of the number of bytes that can be stored in a row - then you should split it out.
Or if you will normally be querying the main table separately and won't need those fields much of the time.
If some columns is (not identifiable or dependent on the primary key) or (values from a definite/fixed set is being used repeatedly) of the Table make a Different Table for those columns and maintain a one to one relationship.
Why not have a User table and Features table, e.g.:
create table User ( id int primary key, name varchar(255) ... )
create table Features (
user_id int,
feature varchar(50),
enabled bit,
primary key (user_id, feature)
)
Then the data in your Features table would look like:
| user_id | feature | enabled
| -------------------------------
| 291 | show_photos | 1
| -------------------------------
| 291 | show_name | 1
| -------------------------------
| 292 | show_photos | 0
| -------------------------------
| 293 | show_name | 0
I would suggest something differnet. It seems likely that in the future you will be asked for 'yet another attribute' to manage. Rather than add a column, you could just add a row to an attributes table:
TABLE Attribute
(
ID
Name
)
TABLE User
(
ID
...
)
TABLE UserAttributes
(
UserID FK Users.ID
Attribute FK Attributes.ID
Value...
)
Good comments from everyone. I should have been clearer in my response.
We do this quite a bit to handle special-cases where customers ask us to tailor our site for them in some way. We never 'pivot' the NVP's into columns in a query - we're always querying "should I do this here?" by looking for a specific attribute listed for a customer. If it is there, that's a 'true'. So rather than having these be a ton of boolean-columns, most of which would be false or NULL for most customers, AND the tendency for these features to grow in number, this works well for us.

Efficient Classifieds Mysql Structure

I am restructuring a classifieds MySQL db where the different main sections are separated into separate tables. For example, sale items have their own table with unique ID's, jobs have their own table with unique ID's, personals have their own table as well.
These sections all share a few common characteristics:
-id
-title
-body
-listing status
-poster
-reply email
-posting date
But they each have some separate information required as well:
-each have different sets and trees of categories to choose from (which affect the structure needed to store them)
-jobs need to store things like salary, start date, etc.
-sale items need to store things like prices, obo, etc.
Therefore, is it a better practice to refactor the db while I can to a universal table to store ALL the general listing info regardless of section, and then task out customized data storage to small tables, or is it better to leave the current structure alone and leave the sections separated?
Sounds like they are all separate entities that have nothing to do with each other (ecxept for sharing some column-definitions), right?
Do you ever want to do a SELECT like
SELECT *
FROM main_entity
WHERE entity_type IN ('SALE_ITEM', 'JOB', 'PERSONAL')?
Otherwise I don't think I would merge them into one table.
Don't use a single table. Go relational.
What I would recommend setting up is a so-called polymorphic relationship between your "main" table (the one with the common characteristics), and three tables containing specific information. The structure would look something like this:
Main table
id
title
...
category_name (VARCHAR or CHAR)
category_id (INTEGER)
Category table
id
(specific columns)
The category_name field should contain the table name of the specific category table, eg. 'job_category', while the category_id should point to ID in the category table. An example would look like this:
# MAIN TABLE
id | title | ... | category_name | category_id
-------------------------------------------------------
123 | Some title | ... | job_category | 345
321 | Another title | ... | sale_category | 543
# SPECIFIC TABLE (job_category)
id | ...
---------
345 | ...
# SPECIFIC TABLE (sale_category)
id | ...
---------
543 | ...
Now, whenever you query the main table, you will immediately know which table to fetch the additional data from, and you will know the ID in that table. The only downside to this approach is that you have to perform two separate queries to fetch information for one single item. It would probably be possible to do this in a transaction, however.
For fetching data the other way around (eg. you search the jobs_category for something), on the other hand, you can fetch the associated data from the main table with a JOIN. Remember to not only join main.category_id = jobs_category.id, but also to use the category_name column as a join condition. Otherwise, you may fetch data that belongs to one of the other categories.
For optimal performance, you may want to index the category_name and category_id columns. This would mostly speed up any queries that join the two tables, as described in the previous paragraph.
Hope this helps!