Top N Per Group with Multiple Table Joins

前端 未结 3 926
礼貌的吻别
礼貌的吻别 2020-12-15 12:54

Based on my research, this is a very common problem which generally has a fairly simple solution. My task is to alter several queries from get all results into

3条回答
  •  天命终不由人
    2020-12-15 13:13

    Even though you specify LIMIT 100, this type of query will require a full scan and table to be built up, then every record inspected and row numbered before finally filtering for the 100 that you want to display.

    select
        vendorid, productid, NumSales
    from
    (
        select
            vendorid, productid, NumSales,
            @r := IF(@g=vendorid,@r+1,1) RowNum,
            @g := vendorid
        from (select @g:=null) initvars
        CROSS JOIN 
        (
            SELECT COUNT(oi.price) AS NumSales, 
                   p.productid, 
                   p.vendorid
            FROM products p
            INNER JOIN vendors v ON (p.vendorid = v.vendorid)
            INNER JOIN orders_items oi ON (p.productid = oi.productid)
            INNER JOIN orders o ON (oi.orderid = o.orderid)
            WHERE (p.Approved = 1 AND p.Active = 1 AND p.Deleted = 0)
            AND (v.Approved = 1 AND v.Active = 1 AND v.Deleted = 0)
            AND o.`Status` = 'SETTLED'
            AND o.Deleted = 0
            GROUP BY p.vendorid, p.productid
            ORDER BY p.vendorid, NumSales DESC
        ) T
    ) U
    WHERE RowNum <= 3
    ORDER BY NumSales DESC
    LIMIT 100;
    

    The approach here is

    1. Group by to get NumSales
    2. Use variables to row number the sales per vendor/product
    3. Filter the numbered dataset to allow for a max of 3 per vendor
    4. Order the remaining by NumSales DESC and return only 100

提交回复
热议问题