When should one create a new table in a database and use new ids? Example in a database for tickets for concerts, should I create a new table for each concert then delete it afterwards?
Keeping all the tickets in one database with unique ID's for each does not sound like a scalable solution.
This is a theory question rather than a practical coding question.
Here is a sample example of how you could do this in a relational pattern:
SCHEMA:
Table: USER
+---------------+-------------------+---------------+
| UserID | First Name | Last Name |
+---------------+-------------------+---------------+
| 1 | John | Doe |
|---------------|-------------------|---------------|
| 2 | Jane | Doe |
+---------------+-------------------+---------------+
Table: CONCERT
+---------------+-------------------+-----------+---------------+
| ConcertID | Concert Name | Artist | Date |
+---------------+-------------------+-----------+---------------+
| 1 | Rock Concert | Rob | Jan-1-2014 |
|---------------|-------------------|-----------|---------------|
| 2 | Rap Concert | Jay | Feb-3-2014 |
+---------------+-------------------+-----------+---------------+
Table: TICKET
+-----------+---------------+---------------+
| UserID | ConcertID | Quantity |
+-----------+---------------+---------------+
| 1 | 1 | 1 |
|-----------|---------------|---------------|
| 1 | 2 | 3 |
|-----------|---------------|---------------|
| 2 | 1 | 2 |
+-----------+---------------+---------------+
Raw SQL to create above schema:
CREATE TABLE USER (
`UserID` int unsigned primary key,
`First Name` varchar(4) not null,
`Last Name` varchar(3) not null
) engine=innodb charset=utf8;
INSERT INTO USER
(`UserID`, `First Name`, `Last Name`)
VALUES
(1, 'John', 'Doe'),
(2, 'Jane', 'Doe')
;
CREATE TABLE CONCERT (
`ConcertID` int unsigned primary key,
`Concert Name` varchar(12) not null,
`Artist` varchar(3) not null,
`Date` datetime not null
) engine=innodb charset=utf8;
INSERT INTO CONCERT
(`ConcertID`, `Concert Name`, `Artist`, `Date`)
VALUES
(1, 'Rock Concert', 'Rob', '2014-01-01 00:00:00'),
(2, 'Rap Concert', 'Jay', '2014-02-03 00:00:00')
;
CREATE TABLE TICKET (
`Ticket No` int unsigned primary key auto_increment,
`UserID` int unsigned,
`ConcertID` int unsigned,
Foreign Key(`UserID`) references `USER`(`UserID`),
Foreign Key(`ConcertID`) references `CONCERT`(`ConcertID`)
) engine=innodb charset=utf8;
INSERT INTO TICKET
(`Ticket No`, `UserID`, `ConcertID`)
VALUES
(1, 1, 1),
(2, 1, 2),
(3, 2, 1)
;
You need to break apart your tables in such a way that you have one-to-one or one-to-many relationships without having a many-to-many relationship. By using a simple three table setup as described above, one user can purchase multiple tickets to multiple concerts. However, because of the itermediary table TICKET, we are never left with a many-to-many relationship. This also allows us to maintain referential integrity by tying the UserID in the TICKET table to the UserID in the USER table. In addtion, the ConcertID in the TICKET table to the ConcertID in the CONCERT table.
Finally, we are able to generate some simple queries to pull back information we need by joining the tables together. I've included two sample queries below:
SAMPLE QUERY #1 - Retrieve all tickets of a particular user by first and last name
SELECT
`conc`.`Concert Name`,
`conc`.`Artist`,
`conc`.`Date`,
`tick`.`Ticket No`
FROM `CONCERT` AS `conc`
INNER JOIN `TICKET` AS `tick` ON `conc`.`ConcertID` = `tick`.`ConcertID`
INNER JOIN `USER` AS `user` ON `tick`.`UserID` = `user`.`UserID`
WHERE `user`.`First Name` = "John" AND `user`.`Last Name` = "Doe";
Result:
+--------------------+--------------+---------------------------------+-----------------+
| Concert Name | Artist | Date | Ticket No |
+--------------------+--------------+---------------------------------+-----------------+
| Rock Concert | Rob | January, 01 2014 00:00:00+0000 | 1 |
|--------------------|--------------|---------------------------------|-----------------|
| Rap Concert | Jay | February, 03 2014 00:00:00+0000 | 2 |
+--------------------+--------------+---------------------------------+-----------------+
SAMPLE QUERY #2 - Retrieve total number of tickets for a given concert by artist name
SELECT
COUNT(`tick`.`Ticket No`)
FROM `TICKET` as `tick`
INNER JOIN `CONCERT` AS `conc` ON `tick`.`ConcertID` = `conc`.`ConcertID`
WHERE `conc`.`Artist` = "Rob";
Result:
+--------------------+
| Ticket Count |
+--------------------+
| 2 |
+--------------------+
As an extra note, because we are using foreign key constraints, we have indexes defined on the particular columns. This helps SQL better manage and scale the queries/data leading to continued performance even with large numbers (millions) of rows.
Hope this helps. From here, you should be able to develop a lot of different queries to pull back all the information you desire. An exact working demo of the above code can be found below:
DEMO: sqlfiddle.com
A compromise solution to this would be to create a new table in the same database for each concert, and to delete tables if there are space concerns. This would allow you to keep old data around without cluttering one table too much.
Related
I haven't found any MYSQL many-to-many relationships examples here and in google. What I am looking is to see a very simple example with php+mysql showing database's results. Can anybody write a very simple example?
Example scenario: students and courses at a university. A given student might be on several courses, and naturally a course will usually have many students.
Example tables, simple design:
CREATE TABLE `Student` (
`StudentID` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`FirstName` VARCHAR(25),
`LastName` VARCHAR(25) NOT NULL,
PRIMARY KEY (`StudentID`)
) ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_general_ci
CREATE TABLE `Course` (
`CourseID` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
`Code` VARCHAR(10) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL,
`Name` VARCHAR(100) NOT NULL,
PRIMARY KEY (`CourseID`)
) ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_general_ci
CREATE TABLE `CourseMembership` (
`Student` INT UNSIGNED NOT NULL,
`Course` SMALLINT UNSIGNED NOT NULL,
PRIMARY KEY (`Student`, `Course`),
CONSTRAINT `Constr_CourseMembership_Student_fk`
FOREIGN KEY `Student_fk` (`Student`) REFERENCES `Student` (`StudentID`)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `Constr_CourseMembership_Course_fk`
FOREIGN KEY `Course_fk` (`Course`) REFERENCES `Course` (`CourseID`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB CHARACTER SET ascii COLLATE ascii_general_ci
Find all students registered for a course:
SELECT
`Student`.*
FROM
`Student`
JOIN `CourseMembership` ON `Student`.`StudentID` = `CourseMembership`.`Student`
WHERE
`CourseMembership`.`Course` = 1234
Find all courses taken by a given student:
SELECT
`Course`.*
FROM
`Course`
JOIN `CourseMembership` ON `Course`.`CourseID` = `CourseMembership`.`Course`
WHERE
`CourseMembership`.`Student` = 5678
Here's a quick and dirty example of the SQL involved. I don't see any need to muddy up the concept with php. Just retrieve the set like you would any other.
In this example, there are many names, and many colors. People are allowed to have more than one favorite color, and many people can have the same favorite color. Hence many to many.
***** Tables **********
person
--------
id - int
name - varchar
favColor
-------------
id - int
color - varchar
person_color
------------
person_id - int (matches an id from person)
color_id - int (matches an id from favColor)
****** Sample Query ******
SELECT name, color
FROM person
LEFT JOIN person_color ON (person.id=person_id)
LEFT JOIN favColor ON (favColor.id=color_id)
****** Results From Sample Query *******
Name - Color
---------------
John - Blue
John - Red
Mary - Yellow
Timmy - Yellow
Suzie - Green
Suzie - Blue
etc...
Does that help?
mysql> SELECT * FROm products;
+----+-----------+------------+
| id | name | company_id |
+----+-----------+------------+
| 1 | grechka | 1 |
| 2 | rus | 1 |
| 3 | makaronu | 2 |
| 4 | yachna | 3 |
| 5 | svuniacha | 3 |
| 6 | manka | 4 |
+----+-----------+------------+
6 rows in set (0.00 sec)
mysql> SELECT * FROm company;
+----+----------+
| id | name |
+----+----------+
| 1 | LVIV |
| 2 | KIEV |
| 3 | KHarkiv |
| 4 | MADRID |
| 5 | MILAN |
| 6 | KOR |
+----+----------+
6 rows in set (0.00 sec)
mysql> SELECT * FROm many_many;
+------------+---------+
| product_id | city_id |
+------------+---------+
| 1 | 1 |
| 1 | 3 |
| 2 | 3 |
| 1 | 2 |
| 1 | 4 |
| 2 | 4 |
| 2 | 1 |
| 3 | 1 |
+------------+---------+
8 rows in set (0.00 sec)
mysql> SELECT products.name,company.name FROM products JOIN many_many ON many_
ny.product_id =products.id JOIN company ON company.id= many_many.city_id;
+----------+---------+
| name | name |
+----------+---------+
| grechka | LVIV |
| grechka | KHarkiv |
| grechka | KIEV |
| grechka | MADRID |
| rus | KHarkiv |
| rus | MADRID |
| rus | LVIV |
| makaronu | LVIV |
+----------+---------+
8 rows in set (0.00 sec)
SELECT a.a_id, b.b_id, b.b_desc,
CASE WHEN x.b_id IS NULL THEN 'F' ELSE 'T' END AS selected
FROM a
CROSS JOIN b
LEFT JOIN x ON (x.a_id = a.a_id AND x.b_id = b.b_id)
WHERE (a.a_id = 'whatever')
you can use many-to-many relationship, using a junction table.
CREATE TABLE Student (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
CREATE TABLE Course (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
CREATE TABLE Student_Course (
student_id INT NOT NULL,
course_id INT NOT NULL,
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES Student(id),
FOREIGN KEY (course_id) REFERENCES Course(id)
);
INSERT INTO Student (name) VALUES ('Mike');
INSERT INTO Student (name) VALUES ('Jack');
INSERT INTO Student (name) VALUES ('Henry');
INSERT INTO Course (name) VALUES ('Math');
INSERT INTO Course (name) VALUES ('Science');
INSERT INTO Course (name) VALUES ('History');
INSERT INTO Student_Course (student_id, course_id) VALUES (1, 1);
INSERT INTO Student_Course (student_id, course_id) VALUES (1, 2);
INSERT INTO Student_Course (student_id, course_id) VALUES (2, 2);
INSERT INTO Student_Course (student_id, course_id) VALUES (2, 3);
INSERT INTO Student_Course (student_id, course_id) VALUES (3, 1);
INSERT INTO Student_Course (student_id, course_id) VALUES (3, 2);
INSERT INTO Student_Course (student_id, course_id) VALUES (3, 3);
Establishing a many-to-many relationship between the tables
in a database is usually done for ensuring efficient data processing
and data integrity, as well as for database normalization and data analysis tasks.
Since relational databases don’t allow implementing a direct many-to-many relationship between two tables, handling that kind of relationship can be an intimidating task.
When you need to establish a many-to-many relationship in relational database between two or more tables, the simplest way is to use a Junction Table.
A Junction table in a database, also referred to as a Bridge table or Associative Table, bridges the tables together by referencing the primary keys of each data table. So, that’s a junction table in a nut shell.
I haven't found any MYSQL many-to-many relationships examples here and in google. What I am looking is to see a very simple example with php+mysql showing database's results. Can anybody write a very simple example?
Example scenario: students and courses at a university. A given student might be on several courses, and naturally a course will usually have many students.
Example tables, simple design:
CREATE TABLE `Student` (
`StudentID` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`FirstName` VARCHAR(25),
`LastName` VARCHAR(25) NOT NULL,
PRIMARY KEY (`StudentID`)
) ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_general_ci
CREATE TABLE `Course` (
`CourseID` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
`Code` VARCHAR(10) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL,
`Name` VARCHAR(100) NOT NULL,
PRIMARY KEY (`CourseID`)
) ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_general_ci
CREATE TABLE `CourseMembership` (
`Student` INT UNSIGNED NOT NULL,
`Course` SMALLINT UNSIGNED NOT NULL,
PRIMARY KEY (`Student`, `Course`),
CONSTRAINT `Constr_CourseMembership_Student_fk`
FOREIGN KEY `Student_fk` (`Student`) REFERENCES `Student` (`StudentID`)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `Constr_CourseMembership_Course_fk`
FOREIGN KEY `Course_fk` (`Course`) REFERENCES `Course` (`CourseID`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB CHARACTER SET ascii COLLATE ascii_general_ci
Find all students registered for a course:
SELECT
`Student`.*
FROM
`Student`
JOIN `CourseMembership` ON `Student`.`StudentID` = `CourseMembership`.`Student`
WHERE
`CourseMembership`.`Course` = 1234
Find all courses taken by a given student:
SELECT
`Course`.*
FROM
`Course`
JOIN `CourseMembership` ON `Course`.`CourseID` = `CourseMembership`.`Course`
WHERE
`CourseMembership`.`Student` = 5678
Here's a quick and dirty example of the SQL involved. I don't see any need to muddy up the concept with php. Just retrieve the set like you would any other.
In this example, there are many names, and many colors. People are allowed to have more than one favorite color, and many people can have the same favorite color. Hence many to many.
***** Tables **********
person
--------
id - int
name - varchar
favColor
-------------
id - int
color - varchar
person_color
------------
person_id - int (matches an id from person)
color_id - int (matches an id from favColor)
****** Sample Query ******
SELECT name, color
FROM person
LEFT JOIN person_color ON (person.id=person_id)
LEFT JOIN favColor ON (favColor.id=color_id)
****** Results From Sample Query *******
Name - Color
---------------
John - Blue
John - Red
Mary - Yellow
Timmy - Yellow
Suzie - Green
Suzie - Blue
etc...
Does that help?
mysql> SELECT * FROm products;
+----+-----------+------------+
| id | name | company_id |
+----+-----------+------------+
| 1 | grechka | 1 |
| 2 | rus | 1 |
| 3 | makaronu | 2 |
| 4 | yachna | 3 |
| 5 | svuniacha | 3 |
| 6 | manka | 4 |
+----+-----------+------------+
6 rows in set (0.00 sec)
mysql> SELECT * FROm company;
+----+----------+
| id | name |
+----+----------+
| 1 | LVIV |
| 2 | KIEV |
| 3 | KHarkiv |
| 4 | MADRID |
| 5 | MILAN |
| 6 | KOR |
+----+----------+
6 rows in set (0.00 sec)
mysql> SELECT * FROm many_many;
+------------+---------+
| product_id | city_id |
+------------+---------+
| 1 | 1 |
| 1 | 3 |
| 2 | 3 |
| 1 | 2 |
| 1 | 4 |
| 2 | 4 |
| 2 | 1 |
| 3 | 1 |
+------------+---------+
8 rows in set (0.00 sec)
mysql> SELECT products.name,company.name FROM products JOIN many_many ON many_
ny.product_id =products.id JOIN company ON company.id= many_many.city_id;
+----------+---------+
| name | name |
+----------+---------+
| grechka | LVIV |
| grechka | KHarkiv |
| grechka | KIEV |
| grechka | MADRID |
| rus | KHarkiv |
| rus | MADRID |
| rus | LVIV |
| makaronu | LVIV |
+----------+---------+
8 rows in set (0.00 sec)
SELECT a.a_id, b.b_id, b.b_desc,
CASE WHEN x.b_id IS NULL THEN 'F' ELSE 'T' END AS selected
FROM a
CROSS JOIN b
LEFT JOIN x ON (x.a_id = a.a_id AND x.b_id = b.b_id)
WHERE (a.a_id = 'whatever')
you can use many-to-many relationship, using a junction table.
CREATE TABLE Student (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
CREATE TABLE Course (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
CREATE TABLE Student_Course (
student_id INT NOT NULL,
course_id INT NOT NULL,
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES Student(id),
FOREIGN KEY (course_id) REFERENCES Course(id)
);
INSERT INTO Student (name) VALUES ('Mike');
INSERT INTO Student (name) VALUES ('Jack');
INSERT INTO Student (name) VALUES ('Henry');
INSERT INTO Course (name) VALUES ('Math');
INSERT INTO Course (name) VALUES ('Science');
INSERT INTO Course (name) VALUES ('History');
INSERT INTO Student_Course (student_id, course_id) VALUES (1, 1);
INSERT INTO Student_Course (student_id, course_id) VALUES (1, 2);
INSERT INTO Student_Course (student_id, course_id) VALUES (2, 2);
INSERT INTO Student_Course (student_id, course_id) VALUES (2, 3);
INSERT INTO Student_Course (student_id, course_id) VALUES (3, 1);
INSERT INTO Student_Course (student_id, course_id) VALUES (3, 2);
INSERT INTO Student_Course (student_id, course_id) VALUES (3, 3);
Establishing a many-to-many relationship between the tables
in a database is usually done for ensuring efficient data processing
and data integrity, as well as for database normalization and data analysis tasks.
Since relational databases don’t allow implementing a direct many-to-many relationship between two tables, handling that kind of relationship can be an intimidating task.
When you need to establish a many-to-many relationship in relational database between two or more tables, the simplest way is to use a Junction Table.
A Junction table in a database, also referred to as a Bridge table or Associative Table, bridges the tables together by referencing the primary keys of each data table. So, that’s a junction table in a nut shell.
I haven't found any MYSQL many-to-many relationships examples here and in google. What I am looking is to see a very simple example with php+mysql showing database's results. Can anybody write a very simple example?
Example scenario: students and courses at a university. A given student might be on several courses, and naturally a course will usually have many students.
Example tables, simple design:
CREATE TABLE `Student` (
`StudentID` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`FirstName` VARCHAR(25),
`LastName` VARCHAR(25) NOT NULL,
PRIMARY KEY (`StudentID`)
) ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_general_ci
CREATE TABLE `Course` (
`CourseID` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
`Code` VARCHAR(10) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL,
`Name` VARCHAR(100) NOT NULL,
PRIMARY KEY (`CourseID`)
) ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_general_ci
CREATE TABLE `CourseMembership` (
`Student` INT UNSIGNED NOT NULL,
`Course` SMALLINT UNSIGNED NOT NULL,
PRIMARY KEY (`Student`, `Course`),
CONSTRAINT `Constr_CourseMembership_Student_fk`
FOREIGN KEY `Student_fk` (`Student`) REFERENCES `Student` (`StudentID`)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `Constr_CourseMembership_Course_fk`
FOREIGN KEY `Course_fk` (`Course`) REFERENCES `Course` (`CourseID`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB CHARACTER SET ascii COLLATE ascii_general_ci
Find all students registered for a course:
SELECT
`Student`.*
FROM
`Student`
JOIN `CourseMembership` ON `Student`.`StudentID` = `CourseMembership`.`Student`
WHERE
`CourseMembership`.`Course` = 1234
Find all courses taken by a given student:
SELECT
`Course`.*
FROM
`Course`
JOIN `CourseMembership` ON `Course`.`CourseID` = `CourseMembership`.`Course`
WHERE
`CourseMembership`.`Student` = 5678
Here's a quick and dirty example of the SQL involved. I don't see any need to muddy up the concept with php. Just retrieve the set like you would any other.
In this example, there are many names, and many colors. People are allowed to have more than one favorite color, and many people can have the same favorite color. Hence many to many.
***** Tables **********
person
--------
id - int
name - varchar
favColor
-------------
id - int
color - varchar
person_color
------------
person_id - int (matches an id from person)
color_id - int (matches an id from favColor)
****** Sample Query ******
SELECT name, color
FROM person
LEFT JOIN person_color ON (person.id=person_id)
LEFT JOIN favColor ON (favColor.id=color_id)
****** Results From Sample Query *******
Name - Color
---------------
John - Blue
John - Red
Mary - Yellow
Timmy - Yellow
Suzie - Green
Suzie - Blue
etc...
Does that help?
mysql> SELECT * FROm products;
+----+-----------+------------+
| id | name | company_id |
+----+-----------+------------+
| 1 | grechka | 1 |
| 2 | rus | 1 |
| 3 | makaronu | 2 |
| 4 | yachna | 3 |
| 5 | svuniacha | 3 |
| 6 | manka | 4 |
+----+-----------+------------+
6 rows in set (0.00 sec)
mysql> SELECT * FROm company;
+----+----------+
| id | name |
+----+----------+
| 1 | LVIV |
| 2 | KIEV |
| 3 | KHarkiv |
| 4 | MADRID |
| 5 | MILAN |
| 6 | KOR |
+----+----------+
6 rows in set (0.00 sec)
mysql> SELECT * FROm many_many;
+------------+---------+
| product_id | city_id |
+------------+---------+
| 1 | 1 |
| 1 | 3 |
| 2 | 3 |
| 1 | 2 |
| 1 | 4 |
| 2 | 4 |
| 2 | 1 |
| 3 | 1 |
+------------+---------+
8 rows in set (0.00 sec)
mysql> SELECT products.name,company.name FROM products JOIN many_many ON many_
ny.product_id =products.id JOIN company ON company.id= many_many.city_id;
+----------+---------+
| name | name |
+----------+---------+
| grechka | LVIV |
| grechka | KHarkiv |
| grechka | KIEV |
| grechka | MADRID |
| rus | KHarkiv |
| rus | MADRID |
| rus | LVIV |
| makaronu | LVIV |
+----------+---------+
8 rows in set (0.00 sec)
SELECT a.a_id, b.b_id, b.b_desc,
CASE WHEN x.b_id IS NULL THEN 'F' ELSE 'T' END AS selected
FROM a
CROSS JOIN b
LEFT JOIN x ON (x.a_id = a.a_id AND x.b_id = b.b_id)
WHERE (a.a_id = 'whatever')
you can use many-to-many relationship, using a junction table.
CREATE TABLE Student (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
CREATE TABLE Course (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
CREATE TABLE Student_Course (
student_id INT NOT NULL,
course_id INT NOT NULL,
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES Student(id),
FOREIGN KEY (course_id) REFERENCES Course(id)
);
INSERT INTO Student (name) VALUES ('Mike');
INSERT INTO Student (name) VALUES ('Jack');
INSERT INTO Student (name) VALUES ('Henry');
INSERT INTO Course (name) VALUES ('Math');
INSERT INTO Course (name) VALUES ('Science');
INSERT INTO Course (name) VALUES ('History');
INSERT INTO Student_Course (student_id, course_id) VALUES (1, 1);
INSERT INTO Student_Course (student_id, course_id) VALUES (1, 2);
INSERT INTO Student_Course (student_id, course_id) VALUES (2, 2);
INSERT INTO Student_Course (student_id, course_id) VALUES (2, 3);
INSERT INTO Student_Course (student_id, course_id) VALUES (3, 1);
INSERT INTO Student_Course (student_id, course_id) VALUES (3, 2);
INSERT INTO Student_Course (student_id, course_id) VALUES (3, 3);
Establishing a many-to-many relationship between the tables
in a database is usually done for ensuring efficient data processing
and data integrity, as well as for database normalization and data analysis tasks.
Since relational databases don’t allow implementing a direct many-to-many relationship between two tables, handling that kind of relationship can be an intimidating task.
When you need to establish a many-to-many relationship in relational database between two or more tables, the simplest way is to use a Junction Table.
A Junction table in a database, also referred to as a Bridge table or Associative Table, bridges the tables together by referencing the primary keys of each data table. So, that’s a junction table in a nut shell.
I haven't found any MYSQL many-to-many relationships examples here and in google. What I am looking is to see a very simple example with php+mysql showing database's results. Can anybody write a very simple example?
Example scenario: students and courses at a university. A given student might be on several courses, and naturally a course will usually have many students.
Example tables, simple design:
CREATE TABLE `Student` (
`StudentID` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`FirstName` VARCHAR(25),
`LastName` VARCHAR(25) NOT NULL,
PRIMARY KEY (`StudentID`)
) ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_general_ci
CREATE TABLE `Course` (
`CourseID` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
`Code` VARCHAR(10) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL,
`Name` VARCHAR(100) NOT NULL,
PRIMARY KEY (`CourseID`)
) ENGINE=INNODB CHARACTER SET utf8 COLLATE utf8_general_ci
CREATE TABLE `CourseMembership` (
`Student` INT UNSIGNED NOT NULL,
`Course` SMALLINT UNSIGNED NOT NULL,
PRIMARY KEY (`Student`, `Course`),
CONSTRAINT `Constr_CourseMembership_Student_fk`
FOREIGN KEY `Student_fk` (`Student`) REFERENCES `Student` (`StudentID`)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `Constr_CourseMembership_Course_fk`
FOREIGN KEY `Course_fk` (`Course`) REFERENCES `Course` (`CourseID`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB CHARACTER SET ascii COLLATE ascii_general_ci
Find all students registered for a course:
SELECT
`Student`.*
FROM
`Student`
JOIN `CourseMembership` ON `Student`.`StudentID` = `CourseMembership`.`Student`
WHERE
`CourseMembership`.`Course` = 1234
Find all courses taken by a given student:
SELECT
`Course`.*
FROM
`Course`
JOIN `CourseMembership` ON `Course`.`CourseID` = `CourseMembership`.`Course`
WHERE
`CourseMembership`.`Student` = 5678
Here's a quick and dirty example of the SQL involved. I don't see any need to muddy up the concept with php. Just retrieve the set like you would any other.
In this example, there are many names, and many colors. People are allowed to have more than one favorite color, and many people can have the same favorite color. Hence many to many.
***** Tables **********
person
--------
id - int
name - varchar
favColor
-------------
id - int
color - varchar
person_color
------------
person_id - int (matches an id from person)
color_id - int (matches an id from favColor)
****** Sample Query ******
SELECT name, color
FROM person
LEFT JOIN person_color ON (person.id=person_id)
LEFT JOIN favColor ON (favColor.id=color_id)
****** Results From Sample Query *******
Name - Color
---------------
John - Blue
John - Red
Mary - Yellow
Timmy - Yellow
Suzie - Green
Suzie - Blue
etc...
Does that help?
mysql> SELECT * FROm products;
+----+-----------+------------+
| id | name | company_id |
+----+-----------+------------+
| 1 | grechka | 1 |
| 2 | rus | 1 |
| 3 | makaronu | 2 |
| 4 | yachna | 3 |
| 5 | svuniacha | 3 |
| 6 | manka | 4 |
+----+-----------+------------+
6 rows in set (0.00 sec)
mysql> SELECT * FROm company;
+----+----------+
| id | name |
+----+----------+
| 1 | LVIV |
| 2 | KIEV |
| 3 | KHarkiv |
| 4 | MADRID |
| 5 | MILAN |
| 6 | KOR |
+----+----------+
6 rows in set (0.00 sec)
mysql> SELECT * FROm many_many;
+------------+---------+
| product_id | city_id |
+------------+---------+
| 1 | 1 |
| 1 | 3 |
| 2 | 3 |
| 1 | 2 |
| 1 | 4 |
| 2 | 4 |
| 2 | 1 |
| 3 | 1 |
+------------+---------+
8 rows in set (0.00 sec)
mysql> SELECT products.name,company.name FROM products JOIN many_many ON many_
ny.product_id =products.id JOIN company ON company.id= many_many.city_id;
+----------+---------+
| name | name |
+----------+---------+
| grechka | LVIV |
| grechka | KHarkiv |
| grechka | KIEV |
| grechka | MADRID |
| rus | KHarkiv |
| rus | MADRID |
| rus | LVIV |
| makaronu | LVIV |
+----------+---------+
8 rows in set (0.00 sec)
SELECT a.a_id, b.b_id, b.b_desc,
CASE WHEN x.b_id IS NULL THEN 'F' ELSE 'T' END AS selected
FROM a
CROSS JOIN b
LEFT JOIN x ON (x.a_id = a.a_id AND x.b_id = b.b_id)
WHERE (a.a_id = 'whatever')
you can use many-to-many relationship, using a junction table.
CREATE TABLE Student (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
CREATE TABLE Course (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL
);
CREATE TABLE Student_Course (
student_id INT NOT NULL,
course_id INT NOT NULL,
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES Student(id),
FOREIGN KEY (course_id) REFERENCES Course(id)
);
INSERT INTO Student (name) VALUES ('Mike');
INSERT INTO Student (name) VALUES ('Jack');
INSERT INTO Student (name) VALUES ('Henry');
INSERT INTO Course (name) VALUES ('Math');
INSERT INTO Course (name) VALUES ('Science');
INSERT INTO Course (name) VALUES ('History');
INSERT INTO Student_Course (student_id, course_id) VALUES (1, 1);
INSERT INTO Student_Course (student_id, course_id) VALUES (1, 2);
INSERT INTO Student_Course (student_id, course_id) VALUES (2, 2);
INSERT INTO Student_Course (student_id, course_id) VALUES (2, 3);
INSERT INTO Student_Course (student_id, course_id) VALUES (3, 1);
INSERT INTO Student_Course (student_id, course_id) VALUES (3, 2);
INSERT INTO Student_Course (student_id, course_id) VALUES (3, 3);
Establishing a many-to-many relationship between the tables
in a database is usually done for ensuring efficient data processing
and data integrity, as well as for database normalization and data analysis tasks.
Since relational databases don’t allow implementing a direct many-to-many relationship between two tables, handling that kind of relationship can be an intimidating task.
When you need to establish a many-to-many relationship in relational database between two or more tables, the simplest way is to use a Junction Table.
A Junction table in a database, also referred to as a Bridge table or Associative Table, bridges the tables together by referencing the primary keys of each data table. So, that’s a junction table in a nut shell.
The theme of this question is to maintain the user comments over my website.
I had around 25000 articles on my website(of different categories) and each article has a comments section below it.Since the number of comments increased over 70,000 I decided to divide the articles into various tables depending on its category articles_of_type_category and a corresponding comments table article_category_comments for each table,assuming that it would improve the performance in future (though currently its working fine)
Now I have two questions :
1) Should I divide the database or there will no degradation in performance if table grows further in size?
2)If yes,then I have some problem in SQL for join operation for the new database design.On the comments page for each article I show the comments,name of the person who made the comment and his points.
So suppose user is viewing the article 3, hence I need to obtain the following detail to show on the page of article 3
-------------------------------------------------------------------------------------------
serial#| comment | name_who_made_this_comment | points | gold | silver | bronze
-------------------------------------------------------------------------------------------
| | | | | |
| | | | | |
by joining these three tables
user_details
+----+--------+----------+
| id | name | college |
+----+--------+----------+
| 1 | naveen | a |
| 2 | rahul | b |
| 3 | dave | c |
| 4 | tom | d |
+----+--------+----------+
score (this table stores the user points like stackoverflow)
+----+--------+------+--------+--------+---------+
| id | points | gold | silver | bronze | user_id |
+----+--------+------+--------+--------+---------+
| 1 | 2354 | 2 | 9 | 25 | 3 |
| 2 | 4562 | 1 | 9 | 11 | 2 |
| 3 | 1123 | 7 | 9 | 11 | 1 |
| 4 | 3457 | 0 | 9 | 4 | 4 |
+----+--------+------+--------+--------+---------+
comments (this table stores comment, id of the article on which it was made,and user id)
+----+----------------------------+-------------+---------+
| id | comment | article_id | user_id |
+----+----------------------------+-------------+---------+
| 1 | This is a nice article | 3 | 1 |
| 2 | This is a tough article | 3 | 4 |
| 3 | This is a good article | 2 | 7 |
| 4 | This is a good article | 1 | 3 |
| 5 | Please update this article | 4 | 4 |
+----+----------------------------+-------------+---------+
I tried something like
select * from comments join (select * from user_details join points where user_details.id=points.user_id)as joined_temp where comments.id=joined_temp.u_id and article_id=3;
This is a response to this comment, "#DanBracuk:It would really be useful if you give an overview by naming the tables and corresponding column names"
Table category
categoryId int not null, autoincrement primary key
category varchar(50)
Sample categories could be "Fairy Tale", "World War I", or "Movie Stars".
Table article
articleId int not null, autoincrement primary key
categoryId int not null foreign key
text clob, or whatever the mysql equivalent is
Since the comment was in response to my comment about articles and categories, this answer is limited to that.
I would start with a table with articles and categories. Then use a bridge table to link the both. My advice would be to index the categories in the bridge table. This would speed up the access.
Example of table structure:
CREATE TABLE Article (
id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
title varchar(100) NOT NULL
);
INSERT INTO Article
(title)
VALUES
('kljlkjlkjalk'),
('aiouiwiuiuaoijukj');
CREATE TABLE Category (
id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
name varchar(100)
);
INSERT INTO Category
(name)
VALUES
('kljlkjlkjalk'),
('aiouiwiuiuaoijukj');
CREATE TABLE Article_Category (
id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
article_id int,
category_id int
);
INSERT INTO Article_Category
(article_id, category_id)
VALUES
(1,1),
(1,2);
CREATE TABLE User_Details
(`id` int, `name` varchar(6), `college` varchar(1))
;
INSERT INTO User_Details
(`id`, `name`, `college`)
VALUES
(1, 'naveen', 'a'),
(2, 'rahul', 'b'),
(3, 'dave', 'c'),
(4, 'tom', 'd')
;
CREATE TABLE Score
(`id` int, `points` int, `gold` int, `silver` int, `bronze` int, `user_id` int)
;
INSERT INTO Score
(`id`, `points`, `gold`, `silver`, `bronze`, `user_id`)
VALUES
(1, 2354, 2, 9, 25, 3),
(2, 4562, 1, 9, 11, 2),
(3, 1123, 7, 9, 11, 1),
(4, 3457, 0, 9, 4, 4)
;
CREATE TABLE Comment
(`id` int, `comment` varchar(26), `article_id` int, `user_id` int)
;
INSERT INTO Comment
(`id`, `comment`, `article_id`, `user_id`)
VALUES
(1, 'This is a nice article', 3, 1),
(2, 'This is a tough article', 3, 4),
(3, 'This is a good article', 2, 7),
(4, 'This is a good article', 1, 3),
(5, 'Please update this article', 4, 4)
;
Try this:
SQLFiddle Demo
Best of luck.
70000 elements are not so many. In fact the number is close to nothing. Your problem lies in bad design. I have a table with many millions of records and when I request to the application server which executes complex queries in the backend and it responds in less than a second. So you are definitely doing something in sub-optimal design. I think that a detailed answer would take too much space and effort (as we have a complete science built on your question) which is out of scope in this website, so I choose to point you to the right direction:
Read about normalization (1NF, 2NF, 3NF, BCNF and so on) and compare it to your design.
Read about indexing and other implicit optimizations
Optimize your queries and minimize the number of queries
As to answer your concrete question: No, you should not "divide" your table. You should fix the structural errors in your database schema and optimize the algorithms using your database.