How to get Items in order with limit in mysql - mysql

I have a table Item ( id, itemType). itemType can be from 1-5.
I want to retrieve 2 items of each type using mysql.
I tried
select * from `item` ORDER BY `itemType` limit 2
which gives me 2 items order by type but I want 2 items of each type.
http://sqlfiddle.com/#!9/ef83d/1

You can use below query, even i did not check it with data as I dont have sample data so if you get any issue then you can create a sqlfiddle, so that I can customize query as per you in #sql
SELECT x.id,x.type1 as 'Type'
FROM (SELECT t.*,
CASE
WHEN #type != t.type THEN #rownum := 1
ELSE #rownum := #rownum + 1
END AS rank,
#type := t.type AS 'type1'
FROM item t
JOIN (SELECT #rownum := NULL, #type := '') r
ORDER BY t.type,t.id) X
WHERE x.rank<=2;
Even you can ordering based on top price or any other field.

Related

ranking of data based on multiple columns in mysql with using rank function

i am very new to mysql and tried to rank top records based on two fields
sharing you the current script and output along with the desired output
Current Script :
select u_rank, c_rank,u_name,c_name,
#curRank := #curRank + 1 AS rank
from (
SELECT u_rank, c_rank,u_name,c_name
from abc
) a,
(
select #curRank := 0
) r
order by c_rank,u_rank
Current OutpuT
MY DESIRED OUTPUT IS
Please help
If I am decifering your question correctly, you are wanting to rank the c_ranks ascending or each u_name and then order by that rank then the u_rank. After that you need to get a rank for all records in that order. I'm not sure that the way I just worded that made any sense... but the following should get that result for you:
SET #rank1 = 0;
SET #rank2 = 0;
SET #u_name = '';
SELECT u_rank, c_rank, u_name, c_name, #rank2 := #rank2 + 1 AS rank
FROM (
SELECT u_rank,
c_rank,
c_name,
#rank1 := (#rank1 + 1 - IF(#u_name = u_name, 0, #rank1)) AS rank1,
#u_name := u_name AS u_name
FROM abc
ORDER BY u_name, c_rank
) foo
ORDER BY rank1, u_rank;

MariaDB/MySQL RANK() implementation

I am working on migration from MS SQL Server to MariaDB 10.0. I have query which use RANK() PARTITION BY. I already created some kind of RANK() implementation on my table but it's not working properly.
The original query was:
RANK() OVER (PARTITION BY visits.id_partner ORDER BY visits.updated_at DESC) AS rank
My implementation for MariaDB/MySQL:
SELECT
...,
(
CASE visits.id_partner
WHEN #currId THEN
#curRow := #curRow + 1
ELSE
#curRow := 1 AND #currId := visits.id_partner
END
) AS rank
FROM
records rec
JOIN visits ON visits.id = rec.id_visit,
(
SELECT
#curRank := 0,
#currId := NULL
) r
WHERE
...
ORDER BY visits.id_partner ASC, visits.updated_at DESC
I want to select row ranked by id_partner order by updated_at field. When id_partner is same as on row before RANK should increase by 1. When is different than before, it should reset to 1.
But my query is not working at all. I have still rank 1 on all rows. Can you help me find mistake?
Thank you for help!
It is tricky to use variables in MySQL/MariaDB. A variable should only be used and assigned in one statement (as you do correctly). However, AND can short-circuit variable assignment.
I use a construct like this for ROW_NUMBER(). RANK() is actually a bit of a pain . . . DENSE_RANK() and ROW_NUMBER() are simpler. However, this seems to be the code that you are aiming for:
SELECT ...,
(#rn := if(#currId = visits.id_partner, #rn + 1,
if(#currId := visits.id_partner, 1, 1)
)
) as rank
FROM records rec JOIN
visits
ON visits.id = rec.id_visit CROSS JOIN
(SELECT #rn := 0, #currId := NULL) params
WHERE
...
ORDER BY visits.id_partner ASC, visits.updated_at DESC;
EDIT:
In MySQL (and presumably in MariaDB), sometimes variables don't work quite right unless you use a subquery. So, try this:
SELECT . . .,
(#rn := if(#currId = visits.id_partner, #rn + 1,
if(#currId := visits.id_partner, 1, 1)
)
) as rank
FROM (SELECT ...
FROM records rec JOIN
visits
ON visits.id = rec.id_visit
WHERE
...
ORDER BY visits.id_partner ASC, visits.updated_at DESC
) t CROSS JOIN
(SELECT #rn := 0, #currId := NULL) params;

MySQL Ranking ID with Ties Based on Column Returns Error

I have a 1 table database with (in a simplified form) the following fields:
user_id(INT), ref_id(INT), points(INT), pointsgiven(BOOL/TINY_INT)
I want a query that returns the RANK of the user_id I specify based on points, given that pointsgiven is true. The kicker is, I need ties included. I can get a result set for ALL ranks if I want with the following query
SELECT
user_id, ref_id, points, pointsgiven,
CASE
WHEN #points = COALESCE(points, 0) THEN #rownum
ELSE #rownum := #rownum + 1
END AS rank,
#points := COALESCE(points, 0)
FROM users CT
JOIN
(
SELECT #rownum := 0, #points := NULL
) r
WHERE pointsgiven=TRUE ORDER BY points DESC
So, based on that, I thought I could just use that as a subquery to get a certain user_id as follows:
select * from
(
SELECT
user_id, ref_id, points, pointsgiven,
CASE
WHEN #points = COALESCE(points, 0) THEN #rownum
ELSE #rownum := #rownum + 1
END AS rank,
#points := COALESCE(points, 0)
FROM users CT
JOIN
(
SELECT #rownum := 0, #points := NULL
) r
WHERE pointsgiven=TRUE ORDER BY points DESC
) as derived WHERE user_id = 15
But this returns [BLOB - 1 B] as the rank on the correct user_id. What am I doing wrong here?
I have no idea why your query isn't working. For a single user id, though, you can use a correlated subquery:
select user_id, ref_id, points, pointsgiven,
coalesce((select count(distinct user_id)
from users u2
where u2.pointsgiven=TRUE and
u2.points > u.points
) + 1, 1) as rank
from users u
where user_id = 15;
An index on users(pointsgiven, points, user_id) should be used by the query.
To look at just one ranking, this might even be faster than your method.

Analytic mysql function to retrieve rows of each category depending on another column

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.

Mysql selecting top 10 of each category analytic function

I have a table which has the following two columns including others: rating, price and code. Ratings is similar to a category. I wish to generate the top 10 for each rating order by price ascending where code = 'ABC'. I'm at a loss to figure out where to put the last two conditions in the following mysql statement. Please can someone advise. Many thanks
SELECT 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 offers t
JOIN (SELECT #rownum := NULL, #rating := '') r
ORDER BY t.rating) x
WHERE x.rank <= 10
ALso, what if the rating column had entries like 1, 1, 1k, 1*, 1+, 2, 2, 2+, 3,3,3* etc, how would I be able to consider all of these entries as '1', 2 and 3 respectively in the same sql statement?
Try this:
SELECT 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 offers t
JOIN (SELECT #rownum := NULL, #rating := '') r
WHERE code = 'ABC'
ORDER BY t.rating, price) x
WHERE x.rank <= 10
The changes are:
Added a WHERE clause after the JOIN clause
Added price to the ORDER BY clause.