Reputation: 12542
I have two tables, one with arbitrary rows of books and one with specific rows of subjects and ids.
mysql> describe books;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| title | varchar(250) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
mysql> describe subjects;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| subjects | varchar(250) | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
I want to associate one book to many subject ids, is there any array type I can use so that one column in my books table contains an array of different subject ids?
Can I then do a query on the books table to see which books are related to one subject?
Upvotes: 1
Views: 2965
Reputation: 108370
This is a many-to-many relationship, not a one-to-many relationship. (A book can have several subjects, and a subject can have several books.)
The normative pattern is to implement a third table to store the "relationship" between books and subjects.
As an example of a minimal relationship table:
CREATE TABLE books_subjects
( subjects_id INT(11) NOT NULL COMMENT 'PK, FK ref subjects(id)'
, books_id INT(11) NOT NULL COMMENT 'PK, FK ref books(id)'
, PRIMARY KEY (subjects_id, books_id)
);
For InnoDB, we can define the foreign key constraints:
ALTER TABLE books_subjects ADD CONSTRAINT FK_books_subjects_books
FOREIGN KEY (books_id) REFERENCES books(id);
ALTER TABLE books_subjects ADD CONSTRAINT FK_books_subjects_subjects
FOREIGN KEY (subjects_id) REFERENCES subjects(id);
This effectively resolves the many-to-many relationship into two one-to-many relationships.
A books
can have multiple books_subjects
, but a books_subjects
is related to exactly one books
.
A subjects
can have multiple books_subjects
, but a books_subjects
is related to exactly one subjects
.
Queries to retrieve books
related to a particular subjects
would involve a JOIN operation to the books_subjects
table.
For example, to find all books
of particular subjects
:
SELECT b.id
, b.title
FROM books b
JOIN books_subjects j
ON j.books_id = b.id
JOIN subjects s
ON s.id = j.subjects_id
WHERE s.subjects = 'Psychology'
ORDER BY b.title
To find books
that don't have any subjects
, e.g.
SELECT b.id
, b.title
FROM books b
LEFT
JOIN books_subjects j
ON j.books_id = b.id
WHERE j.books_id IS NULL
ORDER BY b.title
NOTE: I typically use singular names for tables. So, there would be a lot fewer "s" characters in my column names and foreign key names. I may have omitted an "s" or two in my typing.
Upvotes: 4