The following is working and readable SQL for Eloquent that I have created. The downside is that it looks more like a 1:1 with SQL and I don't think I'm using the full potential of Eloquent. I thought of using scope queries to shorten it, but for some reasons the selectRaw
prevents it (due to multiple join variable scopes).
Data is scattered across three tables and modifying the tables is not an option.
Notes:
$genreIdList
is an array of IDs,$limit
is the max number of results requested,$offset
is the starting point of the pull,selectRaw
is necessary as the selected columns are needed.
Here is the original SQL:
SELECT
b.title,
GROUP_CONCAT(DISTINCT(g.name) ORDER BY relevancy, g.name ASC SEPARATOR ' ') as genre_list,
GROUP_CONCAT(DISTINCT CAST(relevancy as char) ORDER BY relevancy ASC SEPARATOR ',') as genre_relevancy,
bg.book_id
FROM book_genres bg
INNER JOIN genre_book g ON bg.genre_id = g.id AND g.id IN (". (($genreIdList) ? $genreIdList : 0) . ")
INNER JOIN book b ON bg.book_id = b.id
INNER JOIN licensors l ON b.licensor_id = l.id
WHERE b.status = 'active' AND b.premium = 'yes' AND l.status = 'active'
GROUP BY bg.book_id
This is the PHP/Eloquent version:
$relatedBooks = Book::selectRaw("book.title,
GROUP_CONCAT(DISTINCT(gb.name) ORDER BY bg.relevancy, gb.name ASC SEPARATOR ' ') as genre_list,
GROUP_CONCAT(DISTINCT CAST(bg.relevancy as char) ORDER BY bg.relevancy ASC SEPARATOR ',') as genre_relevancy,
bg.book_id ")
->join('book_genres AS bg', 'bg.book_id', '=', 'book.id')
->join('genre_book AS gb', 'gb.id', '=', 'bg.genre_id')
->join('licensors AS l', 'l.id', '=', 'book.licensor_id')
->whereIn('gb.id', $genreIdList)
->where('book.premium', '=', 'yes')
->where('book.status', '=', 'active')
->where('l.status', '=', 'active')
->take($limit)
->offset($offset)
->get();
groupBy('book.id')
onBooks
table ? looks like the Books table has many books with same ID, which is not good in most cases. can you update the post with table structures and sample output you are expecting ? \$\endgroup\$