MySQL Many-to-many търсене?

Laraveren

Registered
Здравейте,

Извинявам се че Ви занимавам с такъв въпрос но от 2 дена търся решение и не се справям а почвам да "полудявам" от това че съм толкова тъп.

Идеята е следната - ще използвам класичесният пример с книгата и авторите.

Една книга може да има повече от един автор.
Един автор може да има повече от една книга.

Добре ето как изглеждат нещата в SQL:

books

Код:
+---------+------------------------+
| id      | name                   |
+---------+------------------------+
| 1       | Hello Code             |
| 2       | First Time Code        |
| 3       | My Name Is             |
| 4       | The Book of Books      |
| 5       | My New Smile           |
+----------------------------------+

authors

Код:
+---------+------------------------+
| id      | name                   |
+---------+------------------------+
| 1       | Ivan Ivanov            |
| 2       | Dragan Draganov        |
| 3       | Petko Petkov           |
| 4       | Stanislav Stanev       |
| 5       | Nikolai Nikolov        |
| 6       | Gandal Gandalov        |
| 7       | Petyr Petrov           |
+----------------------------------+

Така реализацията която е използвана е таблица за връзката - много към много:

book_author

Код:
+---------------------------+
| id  | book_id | author_id |
+-----+---------+-----------+
| 1   | 1       | 1         |
| 2   | 1       | 2         |
| 3   | 1       | 3         |
| 4   | 2       | 1         |
| 5   | 2       | 2         |
| 6   | 3       | 1         |
| 7   | 3       | 2         |
| 8   | 4       | 1         |
| 9   | 5       | 2         |
| 10  | 5       | 3         |
| 11  | 5       | 4         |
| 12  | 5       | 5         |
+-----+---------+-----------+

Като цяло няма кой знае какво сложно - да и аз така си мислих но до тук :)))

Идеята е следната - как да се пусне търсене което да казва - намери ми книга която е на автори с ID - 1 и 2 и двамата да участват в нея книга и ми покажи само нея/тях?

Може би ще кажете - много просто - е да ала за мен не е :)

Код:
SELECT *
FROM books
LEFT JOIN book_author ON books.id = book_author.book_id
LEFT JOIN authors ON book_author.author_id = authors.id
WHERE book_author.author_id =1
AND book_author.author_id =2
LIMIT 0 , 30

- не ми дава резултатити - май е логично де :)))


При ползване на IN:

Код:
SELECT *
FROM books
LEFT JOIN book_author ON books.id = book_author.book_id
LEFT JOIN authors ON book_author.author_id = authors.id
WHERE book_author.author_id
IN ( 1, 2 )
LIMIT 0 , 30

Показва ми книгите където участват авторите с id: 1 и 2. Аз искам да ми показва книгите където те двамата участват заедно! А не просто да ми намира книги с 1 и 2 :) Най-вероятно така съм му казал - де :) Но има ли някакъв начин - че това ме убива вече няколко дена? :)
 
В book_author не ти трябва поле id, нека първичния ключ да е на другите 2 полета, в цялостта си те са уникални
За заявката:

[sql]SELECT *
FROM `books`
INNER JOIN `book_author` ON `books`.`id` = `book_author`.`book_id`
INNER JOIN `author` ON `book_author`.`author_id` = `author`.`id`
WHERE `author`.`name` = 'Първия автор' OR `author`.`name` = 'Втория автор'
GROUP BY `books`.`id`
HAVING COUNT(`book_author`.`book_id`)=2[/sql]

Друг по-традиционен подход е заявка от заявка, но за мен този се е доказал като по-бърз :?:
 
raiden каза:
В book_author не ти трябва поле id, нека първичния ключ да е на другите 2 полета, в цялостта си те са уникални
За заявката:

[sql]SELECT *
FROM `books`
INNER JOIN `book_author` ON `books`.`id` = `book_author`.`book_id`
INNER JOIN `author` ON `book_author`.`author_id` = `author`.`id`
WHERE `author`.`name` = 'Първия автор' OR `author`.`name` = 'Втория автор'
GROUP BY `books`.`id`
HAVING COUNT(`book_author`.`book_id`)=2[/sql]

Друг по-традиционен подход е заявка от заявка, но за мен този се е доказал като по-бърз :?:
Ако иска да проверява за повече от 2-ма автори, да допълня за този ред:

[sql]WHERE `author`.`name` = 'Първия автор' OR `author`.`name` = 'Втория автор'
[/sql]
да стане така:

[sql]WHERE `author`.`name` in ('автор1', 'автор2', 'автор3')[/sql]

Просто ще му е по-лесно да ги свърже при повече автори :)
 
А сега де :)

Като за начало имаш реалативна табличка book_author, и понеже търсим чрез чрез id на автор - започваме от нея. Навързваме си books и authors. До тук добре, но се търси обратната релация - от id на книга - id на автор. За тази цел правим втора връзка към релативната табличка по книга. За да изведем резултата с авторите - правим втрора връзка с authors през втората релативна табличка.

[sql]
SELECT
b.id,
b.name as title,
a.id,
CONCAT_WS(', ', a.name, a2.name) as authors
FROM books_author ba
JOIN books b ON b.id = ba.id
JOIN authors a ON a.id = ba.id
JOIN books_authors ba2 ON ba2.book_id = b.id
JOIN authors a2 ON a2.id = ba2.author_id
WHERE ba.id = 1
AND ba2.id = 2
[/sql]
 
Като цяло не се разбира идеята която искаш да осъществиш, но ако съм те разбрал правилно искаш да търсиш нещо в база данни. Това за да стане, от потребителска гледна точка, трябва да се търси по име на автор и книга, а не ID или каквото и да било, тъй като потребителя потърсил информация, няма как да знае коя книга или автор на кое ID отговаря.
 

Back
Горе