简体   繁体   中英

MySql - SUM() of column in child table (1:n) in a Sub-query/Outer Join using LIMIT

I have two tables - PRODUCT, ACTIVITY. Each product can have multiple activity (1:n). Each activity has an (INT) action column. I need to query all the products and the SUM(product.action) of the 10 most recent activities.

My first attempt was to use a sub-query:

select p.*, (select sum(a.action) from activity a 
        where a.product_id = p.product_id
        order by a.timestamp desc limit 10) recent
from product p

However, the result was incorrect. I realized that the sub-query wasn't using the LIMIT and was returning the SUM() of all ACTIVITY records matching the product_id.

My second attempt was to follow the advice here and wrap the sub-query in another select query:

select p.*, (select sum(temp.action) as recent
from (select a.action from activity a 
        where a.product_id = p.product_id 
        order by a.timestamp desc limit 10) temp)
from product p

However, I got the error message Error Code: 1054. Unknown column 'p.product_id' in 'where clause'. I found a related question here and realized that MYSQL doesn't support alias on 2nd level nesting. I didn't quite follow the answer for that question.

I also tried an outer join

select p.*, sum(temp.action) as recent
from product p
left join
(select a.product_id, a.action from activity a 
        where a.product_id = p.product_id
        order by a.timestamp desc limit 10) temp
on p.product_id= temp.product_id

Again, I ran into the same issues:

  1. The LIMIT is not enforced
  2. The alias is not recognized

How do I fix this?

1- Get distinct products from your product table
2- Get the ten most recent activities for each product
3- Get sums from (2)
4- Join

Take a look at Using LIMIT within GROUP BY to get N results per group? . It sounds similar to what you need for (2).

EDIT

I modified the query slightly and tested it on a small dataset. The previous version did not work because the where clause was in the wrong place. See below.

select t.product_id, sum(t.action) from
(
    select product_id, action, timestamp, 
    @row_num := if(@prev = product_id, @row_num + 1, 1) as row_num, @prev := product_id 
    from activity
    join (select @prev := null, @row_num := 0) as vars
    order by product_id, timestamp desc
) as t
where t.row_num <= 10
group by t.product_id;

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM