I am building a project with Laravel and I have a table which contains all my products. On that table, products get added daily, and I show all products on my page sorted by created_at
. That’s a pretty easy job to do with Laravel Eloquent and ->orderBy('created_at', 'DESC')
.
However, I want to have the possibility to "hold up"/"pin" certain products to a certain place. For that, I have created the column rank_index
which contains the number the product should have in the returned query collection.
This is my current table:
title rank_index created_at
An awesome product 2023-01-01 10:04:00
Another product 4 2023-01-01 10:00:00
Baby car 2023-01-01 10:05:00
Green carpet 2 2023-01-01 10:08:00
Toy 2023-01-01 10:07:00
And the following table shows the collection I want my query to return:
title rank_index created_at
Toy 2023-01-01 10:07:00
Green carpet 2 2023-01-01 10:08:00
Baby car 2023-01-01 10:05:00
Another product 4 2023-01-01 10:00:00
An awesome product 2023-01-01 10:04:00
Preferably, I would like to have a solution which directly returns me the table like this from the database. This way I don’t have to split and slice the collection, which makes the request much slower! Otherwise, I have to rearrange, split and slice the collection with PHP functions.
I am happy about any help!
Kind regards
2
Answers
I encountered this years back and its quite complicated to do the sorting directly in the query, you can refer to this question MySQL result set ordered by fixed positions if you want to dig in to its complexity.
What I did before was a bit simpler and done with two queries,
Heres an example you can refer
I would almost certainly go with silver’s solution
Your statement:
makes little sense. Splitting/slicing/splicing the two result sets together is unlikely to have a measurable impact on performance. It certainly won’t make the "request much slower"!
Here is a SQL solution to your scenario, but it will almost certainly be slower than splicing the two result sets together, depending on the size of the tables involved.
If you have more than 1000
toys
the recursive cte will hit the default cte_max_recursion_depth, as explained here.You could run the following before the above query to remove the limit:
or change the RECURSIVE CTE to a non-recursive one with ROW_NUMBER() on the full
toys
table:Here is a db<>fiddle to play with.