I have 2 tables :
How do i output all categories in the database with 5 businesses in each category ?
For example, if there are 3 categories in the db, then I want :
category 1
--------------
business 1
business 2
business 3
business 4
business 5
category 2
---------------
business 6
business 7
business 8
business 9
business 10
category 3
------------------
business 11
business 12
business 13
business 14
business 15
The only way I know how to do it is fetch all the categories from db and then programmatically loop through each of them and fire another query to get all businesses in each category.
Any other way of doing it ?
You could use rank method but this involve subquery.
select id,business_name,cat_name,cat_id from
(SELECT *,@i := CASE WHEN ( @temp_bid <> m.id ) THEN 1
ELSE @i+1
END AS rank ,
@temp_bid:=m.id as dlset
FROM
( Select a.id as id,a.name as business_name,b.name as cat_name,b.id as cat_id
from business a left outer join categories b on a.id=b.business_id ) m)k,
(SELECT @i:=0)i,(SELECT @i2:=0)i2
where rank<=5
ORDER BY business_name,rank desc;
You can do this with a correlated subquery in the WHERE clause:
select b.name, c.id
from categories c join
business b
on c.business_id = b.id
where c.id in (select c2.id
from categories c2
where c2.business_id = c.business_id
order by rand()
limit 5
)
In other database that support ranking functions, this is much simpler.
If the limit isn't supported in this subquery, then you have to do it with a self-join. Yuck, yuck, yuck:
with bc as (
select b.name, c.id
from categories c join
business b
on c.business_id = b.id
)
select bc.name, bc.id
from bc join
bc bcprev
on bc.name = bcprev.name and
bcprev.id <= bc.id
group by bc.name, bc.id
having count(*) <= 5
This doesn't get 5 random categories. Instead, it gets the five with the lowest ids.
EDIT BY ROSS SMITH:
The above query returns an error in MySQL 5.5.25, but the following works:
select bc.name, bc.id
from
(
select b.name, c.id
from categories c join
business b
on c.business_id = b.id
) bc join
(
select b.name, c.id
from categories c join
business b
on c.business_id = b.id
) bcprev
on bc.name = bcprev.name and
bcprev.id <= bc.id
group by bc.name, bc.id
having count(*) <= 5
and seems to return this expected result.
Wouldn't it be better if you stored the category-business relationship in a separate table? If so, then you can use this query:
SELECT
c_name,
b_name
FROM
(
SELECT
c.name AS c_name,
b.name AS b_name,
(@row := IF(@last = cat_id, @row + 1, 1)) AS row,
@last := cat_id
FROM
(SELECT @row := 0, @last = '') a,
cat_bus cb
INNER JOIN
cat c ON c.id = cb.cat_id
INNER JOIN
bus b ON b.id = cb.bus_id
ORDER BY
c.name,
b.name
) d
WHERE
d.row <= 5
ORDER BY
c_name,
b_name
See sqlfiddle.com for the result.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.