I am trying to return a limited of number of products per brand. The tables are
brands:
id, name
products:
id, brand_id, name
What I am trying to achieve is a query that will output brands.name and products_name 10 times for each brand.
I have tried joining the two tables but when it comes to applying the limit I can't see the next step. Is this possible or will I have to opt to do the brand query first and then query again on a foreach this being more processor intensive?
Get 10 records per product from the second table by the following query:
SELECT *
FROM(
SELECT id, brand_id, name, #n := IF(#r = brand_id, #n + 1, 1) AS rownum,
#r := brand_id
FROM product, (SELECT #r := 0, #n := 0) a
ORDER BY brand_id, id
) a
WHERE a.rownum <= 10;
And join it with brand table, e.g.:
SELECT *
FROM brand b
JOIN (SELECT *
FROM(
SELECT id, brand_id, name, #n := IF(#r = brand_id, #n + 1, 1) AS rownum,
#r := brand_id
FROM product, (SELECT #r := 0, #n := 0) a
ORDER BY brand_id, id
) a
WHERE a.rownum <= 10
) p on b.id = p.brand_id;
Here's the SQL Fiddle.
Related
I have mysql table called ware_stock_transaction and it has order_no, order_type, created_date, item_no.
I want to get the last 10 record from each item, like this:
item A (10 records)
item B (10 records)
item C (10 records)
In MySQL, you can use variables:
select wst.*
from (select wst.*,
(#rn := if(#i = item_no, #rn + 1,
if(#i := item_no, 1, 1)
)
) as rn
from ware_stock_transaction wst cross join
(select #rn := 0, #i := '') params
order by item_no, created_date desc
) wst
where rn <= 10;
I am trying to get the rank of specified record, and I have some success with this code:
SELECT `rank`
FROM
(
select #rownum:=#rownum+1 `rank`, p.*
from TableName p, (SELECT #rownum:=0) r
order by point DESC
) s
WHERE names = 'house'
(See the schema here.)
This SQL query works, but if I want to get the result according to city_id and name, I must use two where clauses, and then the code doesn't work.
I want to get rank of house only for its city. How can I do this?
I want to get rank of "house" only for its city
You can do this by introducing another variable to keep track of the city:
SELECT `rank`
FROM (select p.*,
(#rn := if(#c = city, #rn + 1,
if(#c := city, 1, 1)
)
) as rank
from TableName p CROSS JOIN
(SELECT #rn := 0, #c := -1) params
order by city_id, point DESC
) s
WHERE names = 'house' ;
You can also use your original query, with a tweak, if you know that "house" only appears once in the data:
SELECT `rank`
FROM (select p.*, (#rn := #rn + 1) as rank
from TableName p CROSS JOIN
(SELECT #rn := 0) params
where city_id = (select city_id from TableName t2 where t2.names = 'house')
order by point DESC
) s
WHERE names = 'house' ;
I have the table with data:
And for this table I need to create pegination by productId column. I know about LIMIT N,M, but it works with rows and not with groups. For examle for my table with pegination = 2 I expect to retrieve all 9 records with productId = 1 and 2 (the number of groups is 2).
So how to create pegination by numbers of groups ?
I will be very thankfull for answers with example.
One way to do pagination by groups is to assign a product sequence to the query. Using variables, this requires a subquery:
select t.*
from (select t.*,
(#rn := if(#p = productid, #rn + 1,
if(#rn := productid, 1, 1)
)
) as rn
from table t cross join
(select #rn := 0, #p := -1) vars
order by t.productid
) t
where rn between X and Y;
With an index on t(productid), you can also do this with a subquery. The condition can then go in a having clause:
select t.*,
(select count(distinct productid)
from t t2
where t2.productid <= t.productid)
) as pno
from t
having pno between X and Y;
Try this:
select * from
(select * from <your table> where <your condition> group by <with your group>)
LIMIT number;
I have multiple groups of cities in my dataset and I am trying to rank order price for each of those groups in mysql. Can someone help me convert the partition clause to mysql?
I am presuming that you are looking for the equivalent of rank() over (partition by city order by price). You can do this with a subquery:
select d.*,
(select 1 + count(price)
from dataset d2
where d2.city = d.city and d2.price < d.price
) as rank
from dataset d;
Or using variables:
select d.*,
(#rn := if(#city = city and #price > price, if(#price = #price, #rn + 1, #rn + 1),
if(#city = city and #price = price, #rn,
if(#city := city, if(#price := price, 1, 1), 1)
)
)
) as rank
from dataset d cross join
(select #rn := 0, #city := '', #price = -1)
order by city, price;
I have a table with numerous columns including category and rating. In the entire table, there are two category values: category 1 and category 2. Rating values range from 1 to 5. The following anayltic query retrieves 4 products of each rating irrespective of category, so, 4 products with rating 1, four products with rating 2 and so on... The (id > 10) is of no particular significance)
SELECT
DISTINCT x.*
FROM
(SELECT t.*,
CASE WHEN #rating != t.rating THEN #rownum := 1
ELSE #rownum := #rownum + 1 END
AS rank,
#rating := t.rating
AS var_rating
FROM products t
JOIN (
SELECT #rownum := NULL, #rating := ''
) r
WHERE ( id > 10 )
ORDER BY t.rating, price
) x
WHERE
x.rank <= 4
I wish to modify it to retrieve 4 products of each rating of each category. Please can someone help.
Many thanks
This page is fantastic at the "select-n-per-group" problem.
I'm basically following it in my solution.
These queries selects the 4 cheapest products per (category,rating). In the case of a tie in price it picks the one with the smaller id.
If you just wanted 4 products per (category,rating) regardless of price then skip out the p.price<=products.price line.
Method 1 (easy to understand):
SELECT *
FROM products
where (
select count(*) from products as p
where p.category = products.category
and p.rating = products.rating
and p.price <= products.price
and p.id < products.id -- in case of tie with price
) < 4
ORDER BY category,rating,price;
The inner query says to count up how many items are cheaper than or the same price as you, and the outer query says to pick only things that have less than 4 items cheaper than/same price as you.
If you want to use user variables you can try:
SET #num := 0, #cat := '', #rating := '';
SELECT category,rating,id,price
FROM (
SELECT category,rating,id,price,
#num := if(#cat = category AND #rating=rating, #num + 1, 1) as row_number,
#cat := category as dummy,
#rating := rating as dummy2
FROM products
ORDER BY category,rating,price,id
) AS p WHERE p.row_number <= 4;
Where the inner query orders your table by category, rating, price and id, and assigns row numbers within each (category,rating) pair. The outer query selects the first 4 from each.
The last method on that page would have this query, but it doesn't work unless you have some sort of index on your columns (and my MySQL foo is not enough to work it out):
ALTER TABLE products ADD KEY(???);
SET #num := 0, #cat := '', #rating := '';
SELECT category,rating,id,price,
#num := if(#cat = category AND #rating=rating, #num + 1, 1) as row_number,
#cat := category as dummy,
#rating := rating as dummy2
FROM products FORCE INDEX (???)
GROUP BY category,rating, ???
HAVING row_number <= 2;
which supposedly relies on MYSQL doing an ORDER BY in the GROUP BY and hence making sure rows are ordered as requested.