Get MySQL result where every Nth row is a required item
I have one problem with a mysql query if possible.
Example: we have a table with products, each product has a field type, it can be "free" or "gold". When we search all products by keyword, we get results like
id | product_name | ... | type
---+--------------+-----+-----
1 | ... | ... | free
2 | ... | ... | gold
3 | ... | ... | free
4 | ... | ... | free
5 | ... | ... | free
6 | ... | ... | gold
7 | ... | ... | free
8 | ... | ... | free
9 | ... | ... | gold
10 | ... | ... | free
11 | ... | ... | gold
12 | ... | ... | free
13 | ... | ... | free
14 | ... | ... | gold
15 | ... | ... | free
16 | ... | ... | gold
17 | ... | ... | free
18 | ... | ... | free
19 | ... | ... | free
The problem is: how to order this result to get every fourth string type "gold"
id | product_name | ... | type
---+--------------+-----+-----
1 | ... | ... | free
3 | ... | ... | free
4 | ... | ... | free
2 | ... | ... | gold
5 | ... | ... | free
7 | ... | ... | free
8 | ... | ... | free
6 | ... | ... | gold
10 | ... | ... | free
12 | ... | ... | free
13 | ... | ... | free
9 | ... | ... | gold
15 | ... | ... | free
17 | ... | ... | free
18 | ... | ... | free
11 | ... | ... | gold
19 | ... | ... | free
14 | ... | ... | gold
16 | ... | ... | gold
I don't know how to solve it. Is it possible?
I know how to resolve it using PHP, but I need to know if I can do it using a MySQL query!
+3
source to share
2 answers
You can use the following query:
SELECT id, product_name, type, r
FROM (
SELECT id, product_name, type,
IF((@r1+1) % 4 = 0, @r1:= @r1 + 2, @r1:= @r1 + 1) AS r
FROM mytable, (SELECT @r1:=0) AS var
WHERE type <> 'gold'
ORDER BY id ) t
UNION ALL
SELECT id, product_name, type, r*4 AS r
FROM (
SELECT id, product_name, type,
@r2:= @r2+1 AS r
FROM mytable, (SELECT @r2:=0) AS var
WHERE type = 'gold' ) s
ORDER BY r
Explanation:
- The first part
UNION
extracts all non-gold records and assigns themr
equal values1,2,3,5,6,7,9,..
. - The second part extracts all gold records and assigns them
r
equal values4,8,12,...
. -
ORDER BY r
applies to the entire return setUNION ALL
and provides the desired ordering.
+2
source to share
If you want "gold" on every fourth row, list "gold" and list everything else. Then you can combine the results and use arithmetic to get gold on every fourth line:
select t.*
from ((select t.*, (@rng := @rng + 1) as rn
from table t cross join
(select @rng := 0) params
where type = 'gold'
) union all
(select t.*, (@rn := @rn + 1)
from table t cross join
(select @rn := 0) params
where type <> 'gold'
)
) t
order by (case when type = 'gold' then rn
else 1 + floor((rn - 1) / 3)
end), -- get groups of 3 non-gold and 1 gold
(type = 'gold') , -- put the gold last in the group
id -- order the rest by id
+2
source to share