Best method of organizing database? - mysql

MORE DETAILS:
Both of you recomend using JOIN. But the main problem is how to assign multiple SUBJECTS PER EACH CLASS without using multiple duplicate values. I will have ~200 de classes, with ~30 subjects per class. That means if 2 classes share the same 20 subjects, i will have 40 rows, all with "class_id = 1" but with "subjects_Id =1, subjects_id=2, etc" Its not very ergonomic. Any other ideas? Thanks for your time!
So, I am here again asking for your time and help friends.
I have a database that its almost ok. But I am stuck at trying how to link multiple values from a table to on collumn on another.
Let me be more explicit.
I have this table:
CLASSES
id | class_name | Matters |
-----------------------------
1 | Class1 | 13.4.2013 |
2 | Class2 | 14.4.2013 |
And this table:
Subjects
mat_id | show title |
-----------------
1 | English |
2 | French |
Now the problem is this. Each CLASS (e.g. CLASS1) should be able to study more Subjects at once. For example, CLASS 1 should be linked with subject (mat_id) 1, 3, 5, 6.
How to do this without repeating myself, and optimize the database? I tought that I should do it like so, but its not convenient :
CREATE A NEW TABLE named
SUBJECTS_PER_CLASS
id | class_id | mat_id |
----------------------------
1 | 1 | 1 |
2 | 1 | 3 |
BUT then I dont know how to query it. Any ideas? Any help will be greatly appreciated!
THANKS!

SELECT
*
FROM
CLASSES
JOIN
SUBJECTS_PER_CLASS
ON
CLASSES.ID = SUBJECTS_PER_CLASS.class_id
JOIN
Subjects
ON
Subjects.id = SUBJECTS_PER_CLASS.mat_id

You can use join command.
Reference 1
Reference 2

Related

how to retrieve one to many relationship data in mysql

I have two table
table#1
name_id | name
--------|-------
1 | abc
2 | def
table#2
subject_id| name_id |subject
----------|---------|--------
1 | 1 |malayalam
2 | 1 | english
3 | 1 | hindi
4 | 2 | malayalam
5 | 2 | hindi
i want to join these two tables and get output in the following format
id |name |subject1 |subject2 |subject3
---|-----|--------- |---------|--------
1 |abc |malayalam |english |hindi
2 |def |malayalam |hindi |
is it possible in mySql?
can anyone help?
I'll leave my other answer up because again, I think you should really consider redesigning your DB schema. You're using MySQL so have you tried using group_concat() ? It's not going to put it in table form like that but will give you the expected data, where the different subjects will be in CSV form.
SELECT one.name_id as id, name, group_concat(subject)
FROM one
INNER JOIN two
ON id = two.name_id
GROUP BY id;
Output
1 | abc | malayalam, english, hindi
2 | def | malayalam, hindi
So I'm not exactly sure about the scope of your schema here, because you have a subject_id that doesn't correlate to each subject. For example, subject_id 1 = malayalam but malayalm also equals subject_id 3, but subject_id 3 also equals hindi, while again hindi is also assigned to subject_id 4. Very confusing schema to work with.
You mention it's a one to many, but without knowing more context I don't see that being the case. A person can have more than one subject. One subject can belong to more than 1 person. This is a many to many relationship, which means you should be using 3 tables here.
For the sake of your question, you can use an inner join
SELECT one.name_id as id, name, subject
FROM one
INNER JOIN two
ON id = two.name_id
ORDER BY id;
The output of that query would be:
1 | abc | malayalam
1 | abc | english
1 | abc | hindi
2 | def | malayalam
2 | def | hindi
However, I would highly consider re-designing your database. I mean you want your data in that format, which looks nice with only 3 subjects. But what happens when there's 50 subjects for one person? Would you still want all subjects on one line like that? It's better to break it up, it will save you down the road when your database starts becoming more complex. In many cases, to create a many to many relationship you'll want a 3rd table that connects the two entities, in this case I'd create an Enrolled_Classes table to connect Names and Subjects
Names
name_id | name
--------------
1 | abc
2 | def
Subjects
subject_id | subject
--------------------
1 | malayalm
2 | english
3 | hindi
Enrolled_Classes
name_id | subject_id
--------------------
1 | 1
1 | 2
1 | 3
2 | 1
2 | 3
Then you'd need another join for your query:
SELECT name, subject
FROM Names
INNER JOIN Enrolled_Classes
ON Names.name_id = Enrolled_Classes.name_id
INNER JOIN Subjects
ON Enrolled_Classes.subject_id = Subjects.subject_id;
Same Output
abc | malayalam
abc | english
abc | hindi
def | malayalam
def | hindi

Difficulty in database design

I am experiencing difficulty in MySQL database design.
I have the following tables:
school_table
id | school_name
---------------------------
1 | success primary school
stage_table
id | stage_name
---------------------------
1 | nursery
2 | primary
3 | secondary
school_stage_table
id | school_id | stage_id
---------------------------
1 | 1 | 1
2 | 1 | 2
school_stage_table is a linking table. This is because there is many to many relationship between school and stage, that is a single school may have many stages, and the same stage may have many schools.
The problem comes here:
Each stage has different attributes, and therefore different attribute values for different schools.
How do I model this scenario in a database? Need your help.
As you previously said that you are having some issues that how to store different attributes of each stage of each schools.
Here you can take one table which will store all the attributes of each stage. You can use following table for storing attributes.
Table :
school_stage_attributes_table
id | school_stage_id | attributes_name | attributes_value
------------------------------------------------------------
1 | 1 | attrib_1 | value_1
2 | 1 | attrib_2 | value_2
One option here would be to create a stage_attribute table containing at least the following four columns:
stage_attribute
id | school_id | stage_id | attribute
Each record in this table would correspond to a single attribute for a single stage, e.g.
1 | 1 | 1 | 'nap time'
2 | 1 | 1 | 'breakfast'
3 | 1 | 3 | 'phys ed'
I suspect that some of the difficulty in your mind was with the possibility of adding attribute columns to the stage_table for each attribute. Of course, this is problematical because each stage could have different numbers or types of attributes, and it won't scale for many attributes. The option I gave above eliminates many of these problems by using an arbitrary number of records to store the stage attribute information.
You should use table school_stage_table for this different attribute values for different schools.
If You will use the same attributes schema for multiple schools, then there should be one more table called for example school_stage_options with fields
school_stage_options_id | stage_id | option1 | option2 ....
and later use school_stage_options_id in school_stage_table instead of using stage_id.

MySQL Table structure: Multiple attributes for each item

I wanted to ask you which could be the best approach creating my MySQL database structure having the following case.
I've got a table with items, which is not needed to describe as the only important field here is the ID.
Now, I'd like to be able to assign some attributes to each item - by its ID, of course. But I don't know exactly how to do it, as I'd like to keep it dynamic (so, I do not have to modify the table structure if I want to add a new attribute type).
What I think
I think - and, in fact, is the structure that I have right now - that I can make a table items_attributes with the following structure:
+----+---------+----------------+-----------------+
| id | item_id | attribute_name | attribute_value |
+----+---------+----------------+-----------------+
| 1 | 1 | place | Barcelona |
| 2 | 2 | author_name | Matt |
| 3 | 1 | author_name | Kate |
| 4 | 1 | pages | 200 |
| 5 | 1 | author_name | John |
+----+---------+----------------+-----------------+
I put data as an example for you to see that those attributes can be repeated (it's not a relation 1 to 1).
The problem with this approach
I have the need to make some querys, some of them for statistic purpouses, and if I have a lot of attributes for a lot of items, this can be a bit slow.
Furthermore - maybe because I'm not an expert on MySQL - everytime I want to make a search and find "those items that have 'place' = 'Barcelona' AND 'author_name' = 'John'", I end up having to make multiple JOINs for every condition.
Repeating the example before, my query would end up like:
SELECT *
FROM items its
JOIN items_attributes attr
ON its.id = attr.item_id
AND attr.attribute_name = 'place'
AND attr.attribute_value = 'Barcelona'
AND attr.attribute_name = 'author_name'
AND attr.attribute_value = 'John';
As you can see, this will return nothing, as an attribute_name cannot have two values at once in the same row, and an OR condition would not be what I'm searching for as the items MUST have both attributes values as stated.
So the only possibility is to make a JOIN on the same repeated table for every condition to search, which I think it's very slow to perform when there are a lot of terms to search for.
What I'd like
As I said, I'd like to be able to keep the attributes types dynamical, so by adding a new input on 'attribute_name' would be enough, without having to add a new column to a table. Also, as they are 1-N relationship, they cannot be put in the 'items' table as new columns.
If the structure, in your opinion, is the only one that can acheive my interests, if you could light up some ideas so the search queries are not a ton of JOINs it would be great, too.
I don't know if it's quite hard to get it as I've been struggling my head until now and I haven't come up with a solution. Hope you guys can help me with that!
In any case, thank you for your time and attention!
Kind regards.
You're thinking in the right direction, the direction of normalization. The normal for you would like to have in your database is the fifth normal form (or sixth, even). Stackoverflow on this matter.
Table Attribute:
+----+----------------+
| id | attribute_name |
+----+----------------+
| 1 | place |
| 2 | author name |
| 3 | pages |
+----+----------------+
Table ItemAttribute
+--------+----------------+
| item_id| attribute_id |
+--------+----------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
+--------+----------------+
So for each property of an object (item in this case) you create a new table and name it accordingly. It requires lots of joins, but your database will be highly flexible and organized. Good luck!
In my Opinion it should be something like this, i know there are a lot of table, but actually it normilizes your DB
Maybe that is why because i cant understant where you get your att_value column, and what should contains this columns

MySQL IN() Operator not working

How to use IN() Operator not working it's.
Those table are example and look the same as the real database I have.I don't have the permitting to add tables or change
Those are the tables:
students
+------+------+
| id | name |
+------+------+
| 1 | ali |
| 2 | man |
| 3 | sos |
+------+------+
Classes
+------+---------+
| c_id | students|
+------+---------+
| 1 | 1,2,3,4 |
| 2 | 88,33,55|
| 3 | 45,23,72|
+------+---------+
When I use this query it return me only the student with id =1
because "id IN (students)" return 1 when the first value are equal.
select name,c_id from students,classes where id IN (students);
when I get the list out on PHP than add it. it work fine.But, this solution need a loop and cost many queries.
select name,c_id from students,classes where id IN (1,2,3,4);
FIND_IN_SET()
the same happened, it's only return 1 but if the value on other position it return 0.
The IN operator works just fine, where it's applicable for what it does.
First, consider restructuring your data to be normalized, and avoid storing values as comma separated lists.
Second, if you absolutely have to deal with columns containing comma separated lists of values, MySQL provides the FIND_IN_SET() function.
FOLLOWUP
Ditch the old-school comma syntax for the join operation, and use the JOIN keyword instead. And relocate the join predicates from the WHERE clause to the ON clause. Fully qualify column references, eg.
SELECT s.name
, c.c_id
FROM students s
JOIN classes c
ON FIND_IN_SET(s.student_id,c.students)
ORDER BY s.name, c.c_id
To reiterate, storing a "comma separated list" in a column is an anti-pattern; it flies against relational theory and normalization, and disregards the best practices around relational databases. O
One might argue for improved performance, but this pattern doesn't improve performance; rather it adds unnecessary complexity in query and DML operations.
You need three tables.
One table students, one table classes, and then one table, say, students_to_classes containing something like
c_id | student_id
1 | 1
1 | 2
1 | 3
1 | 4
2 | 88
and so on.
Then you can query
select c_id from students_to_classes where student_id in (1,2,3,4)
Google "n:m relationship" for background on this.
EDIT
I know you're not specifically asking for another table structure, but this is a way of having a data type (a single number) that works with IN. Please believe me that this is the right way to do it, the reason you run into trouble with something as simple as IN is that you're using a non-standard approach, which, for such a standard problem, is typically not a good idea.
That's not how the function IN is supposed to work. You use IN when you have a list of possible matches like:
instead of:
WHERE id=1 or id=2 or id=3 or id=4
you use:
WHERE id IN (1,2,3,4)
Anyhow, your logic is not correct. The relation of Class and Student is Many-to-Many, thus a third table is needed. Let's call it studend_class, where you can store the students of each class.
student
+------+------+
| id | name |
+------+------+
| 1 | ali |
| 2 | man |
| 3 | sos |
+------+------+
class
+------+---------+
| id | name |
+------+---------+
| 1 | math |
| 2 | english |
| 3 | science |
+------+---------+
student_class
+------------+-------------+
| class_id | student_id |
+------------+-------------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 3 | 3 |
+--------------+-----------+
In the example above all students are in math class and ali is also in science class.
Finally, if you whant to know which students are in what class, let's say Math, you can use:
SELECT s.id, s.name, c.name
FROM student s
INNER JOIN student_class sc ON sc.student_id=s.id
INNER JOIN class c ON sc.class_id = c.id
WHERE c.name="math";

SQL - database design, need suggestion

I'm building website where each user has different classes
+----+-----------+---------+
| id | subject | user_id |
+----+-----------+---------+
| 1 | Math 140 | 2 |
| 2 | ART 240 | 2 |
+----+-----------+---------+
Each class then will have bunch of Homework files, Class-Papers files and so on.
And here I need your help. What will be the better approach: Build one table like that:
+----+-----------+--------------------------------------------------+--------------+
| id | subject | Homework | Class-Papers |
+----+-----------+-----------------------------------------------------------------+
| 1 | Math 140 | www.example.com/subjects/Math+140/file_name.pdf | bla-bla |
| 2 | Math 140 | www.example.com/subjects/Math+140/file_name.pdf | bla-bla |
| 3 | Math 140 | www.example.com/subjects/Math+140/file_name.pdf | bla-bla |
| 4 | ART 240 | www.example.com/subjects/ART +240/file_name.pdf | bla-bla |
| 5 | ART 240 | www.example.com/subjects/ART +240/file_name.pdf | bla-bla |
+----+-----------+--------------------------------------------------+--------------+
And than just separate the content when I want to display it,
OR build a table for every single subject and than just load necessary table?
Or if you can suggest something better or more common/useful/efficient please go ahead.
You should read about normalization and relational design before attempting this.
This is a one-to-many relationship - model it as such.
A table for every subject is crazy. You'll have to add a new table for every subject.
A better solution will make it possible to add new subjects simply by adding data. That's what the relational model is all about.
Don't worry about tables; think about it in natural language first.
A SUBJECT(calculus) can have many COURSES(differential, integral, multi-variable).
A COURSE(differential calculus) can have many SECTIONs (Mon 9-10 am in room 2 of the math building).
A STUDENT(first name, last name, student id) can sign up for zero or more SECTIONs. The list of SECTIONs for a given STUDENT is a TRANSCRIPT.
Each STUDENT has one TRANSCRIPT per semester (fall 2012).
A SECTION can have zero or more ASSIGNMENTs.
These are the tables you'll need for this simple problem. Worry about the names and how they relate before you start writing SQL. You'll be glad you did.
I most definitely woudl NOT create a separate table for each subject. If you did, then if you wanted a query like "list all the homework for student X", you would have to access different tables depending on which subjects that student was enrolled in. Worse, anytime someone added a new subject, you would have to create a new table. If down the road you decide you need a new attribute of homework, instead of updating one table, you would have to update every one of these subject tables. It's just bad news all around.