mysql get last 10 records from each group - mysql

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;

Related

How to find median value with group by (MySQL)

Need to find median value of time difference between sent date and click date (in seconds) for each type of emails. I found solution just for all data:
SET #rowindex := -1;
SELECT g.type, g.time_diff
FROM
(SELECT #rowindex:=#rowindex + 1 AS rowindex,
TIMESTAMPDIFF(SECOND, emails_sent.date_sent, emails_clicks.date_click) AS time_diff,
emails_sent.id_type AS type
FROM emails_sent inner join emails_clicks on emails_sent.id = emails_clicks.id_email
ORDER BY time_diff) AS g
WHERE g.rowindex IN (FLOOR(#rowindex / 2) , CEIL(#rowindex / 2));
Is it possible to add group by id_type statement?
Thanks!
First, you need to enumerate the rows for each type. Using variables, this code looks like:
select sc.*,
(#rn := if(#t = id_type, #rn + 1,
if(#t := id_type, 1, 1)
)
) as seqnum
from (select timestampdiff(second, s.date_sent, c.date_click) as time_diff,
s.id_type,
from emails_sent s inner join
emails_clicks c
on s.id = c.id_email
order by time_diff
) sc cross join
(select #t := -1, #rn := 0) as params;
Then, you need to bring in the total number for each type and do the calculation for the median:
select sc.id_type, avg(time_diff)
from (select sc.*,
(#rn := if(#t = id_type, #rn + 1,
if(#t := id_type, 1, 1)
)
) as seqnum
from (select timestampdiff(second, s.date_sent, c.date_click) as time_diff,
s.id_type,
from emails_sent s inner join
emails_clicks c
on s.id = c.id_email
order by time_diff
) sc cross join
(select #t := -1, #rn := 0) as params
) sc join
(select id_type, count(*) as cnt
from emails_sent s inner join
emails_clicks c
on s.id = c.id_email
group by id_type
) n
where 2 * seqnum in (n.cnt, n.cnt, n.cnt + 1, n.cnt + 2)
group by sc.id_type;

Mysql join with limits on joined table

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.

Delete duplicate data except two

How delete duplicate data except two row?
id 4 must deleted, because 'mangga' already have 3 row
This is a bit painful in MySQL. The following identifies the rows to be deleted:
select t.*
from (select t.*,
(#rn := if(#n = nama, #rn + 1,
if(#n := nama, 1, 1)
)
) as rn
from t cross join
(select #n := '', #rn := 0) params
order by nama, id
) t
where rn > 2;
You can then do the delete using a join:
delete t
from t join
(select t.*,
(#rn := if(#n = nama, #rn + 1,
if(#n := nama, 1, 1)
)
) as rn
from t cross join
(select #n := '', #rn := 0) params
order by nama, id
) tt
on t.id = tt.id
where tt.rn > 2;

How to SELECT the total row number as a column

My first query
SELECT
id,
year_,
month_
FROM
(SELECT
tp.id,
YEAR(FROM_UNIXTIME(tp.visited_date)) as year_,
MONTH(FROM_UNIXTIME(tp.visited_date)) as month_,
#rn := IF(#prev = CONCAT(YEAR(FROM_UNIXTIME(tp.visited_date)),MONTH(FROM_UNIXTIME(tp.visited_date))), #rn + 1, 1) AS rn,
#prev := CONCAT(YEAR(FROM_UNIXTIME(tp.visited_date)),MONTH(FROM_UNIXTIME(tp.visited_date)))
FROM
tr_place tp
JOIN
(SELECT #prev := NULL, #rn := 0) AS vars
ORDER BY
YEAR(FROM_UNIXTIME(tp.visited_date)) DESC,
MONTH(FROM_UNIXTIME(tp.visited_date)) DESC) AS T1
WHERE
rn < 3;
Will returns the data set This is the result which I got from the query
The subquery in it
SELECT
tp.id,
YEAR(FROM_UNIXTIME(tp.visited_date)) as year_,
MONTH(FROM_UNIXTIME(tp.visited_date)) as month_,
#rn := IF(#prev = CONCAT(YEAR(FROM_UNIXTIME(tp.visited_date)),MONTH(FROM_UNIXTIME(tp.visited_date))), #rn + 1, 1) AS rn,
#prev := CONCAT(YEAR(FROM_UNIXTIME(tp.visited_date)),MONTH(FROM_UNIXTIME(tp.visited_date)))
FROM
tr_place tp
JOIN
(SELECT #prev := NULL, #rn := 0) AS vars
ORDER BY
YEAR(FROM_UNIXTIME(tp.visited_date)) DESC,
MONTH(FROM_UNIXTIME(tp.visited_date)) DESC;
Returns data The sub query will returns this data
I need the subquery's greatest rn as a column in the first query.
How can I achieve that?
You may be having a problem with variable assignment. You should not be referencing variables in multiple expressions in the select. So, the correct way to write the first query is:
SELECT id, year_, month_
FROM (SELECT tp.id,
YEAR(FROM_UNIXTIME(tp.visited_date)) as year_,
MONTH(FROM_UNIXTIME(tp.visited_date)) as month_,
(#rn := IF (#prev = CONCAT(YEAR(FROM_UNIXTIME(tp.visited_date)), MONTH(FROM_UNIXTIME(tp.visited_date))), #rn,
if(#prev := CONCAT(YEAR(FROM_UNIXTIME(tp.visited_date)), MONTH(FROM_UNIXTIME(tp.visited_date))), 1, 1
)
) as rn
FROM tr_place tp JOIN
(SELECT #prev := NULL, #rn := 0) AS vars
ORDER BY YEAR(FROM_UNIXTIME(tp.visited_date)) DESC,
MONTH(FROM_UNIXTIME(tp.visited_date)) DESC
) t1
WHERE rn < 3;
Note the variable assignments are all in a single expression.
This may fix your issue.

MYSQL - query to select random rows with limitation to parent id

I am trying to create a query that selects 2 random rows for each parent_id from my table.
At the moment my query always returns the first 2 id's for each parent_id. (For example: 1,2 of parent_id=1).
My table is currently as follows:
id, title , parent_id
1, Title1 , 1
2, Title2 , 1
3, Title3 , 1
4, Title4 , 2
5, Title5 , 2
6, Title6 , 2
7, Title7 , 2
8, Title8 , 3
9, Title9 , 3
10, Title10, 3
My current query is:
SELECT id,title,parent_id, rn
FROM (SELECT (#rn := if(#parent_id = parent_id, #rn + 1,
if(#parent_id := parent_id, 1, 1)
)
) as rn,
meals.*
FROM meals CROSS JOIN
(SELECT #rn := 0, #parent_id := '') params
ORDER BY rand()
) meals
WHERE rn <= 2
ORDER BY id ASC
I would like my result to change on each query so for example one result will return the id's 1,3 for parent_id=1 and one will return 2,3 and so on...
Try moving the order by rand() clause into its own derived table
SELECT id,title,parent_id, rn
FROM (SELECT (#rn := if(#parent_id = parent_id, #rn + 1,
if(#parent_id := parent_id, 1, 1)
)
) as rn,
t1.*
FROM ( SELECT * FROM meals CROSS JOIN
(SELECT #rn := 0, #parent_id := '') params
ORDER BY rand() ) t1
ORDER BY parent_id
) meals
WHERE rn <= 2
ORDER BY id ASC
http://sqlfiddle.com/#!9/3310f/1
I think you just need to add parent_id into the order by:
SELECT id, title, parent_id, rn
FROM (SELECT (#rn := if(#parent_id = parent_id, #rn + 1,
if(#parent_id := parent_id, 1, 1)
)
) as rn,
meals.*
FROM meals CROSS JOIN
(SELECT #rn := 0, #parent_id := -1) params
ORDER BY parent_id, rand()
) meals
WHERE rn <= 2
ORDER BY id ASC;
And, if parent_id is a number, there is no reason to make #parent_id a string.