简体   繁体   中英

Limit records for each group before averaging the results overall MySQL

I have a table with the following structure:

doc_date date, doc_type varchar, code int primary key, qty int, price double 

code ranges from 1 - 10; doc_type includes LP, FP, CAS, CRS;

I would like to query the table to get latest (Descending order of doc_date ) N number of records for each code where doc_type is either ' LP ' or ' FP ' and then average price .

I have been able to do everything I require apart from limiting the records for each code before the price is averaged.

My query is:

SELECT a.sfcode, a.productname, COALESCE((b.QTY - COALESCE(c.QTY,0)),0) AS currentstock, a.lastprice AS lprice, COALESCE(CAST(d.price AS decimal(16,3)),0) AS sprice, COALESCE(CAST(e.price AS decimal(16,3)),0) AS cprice FROM 

(SELECT sfcode, productname, lastprice FROM products) AS a LEFT JOIN 

(SELECT sfcode, SUM(COALESCE(QTY, 0)) AS QTY FROM transactions WHERE doctype IN ('FP','LP','CSR') GROUP BY sfcode) AS b ON a.sfcode = b.sfcode LEFT JOIN 

(SELECT sfcode, SUM(QTY) AS QTY FROM transactions WHERE doctype IN ('FPR','LPR','CAS','CRS') GROUP BY sfcode) AS c ON a.sfcode = c.sfcode LEFT JOIN 

(SELECT sfcode, AVG(unitprice) AS price FROM transactions WHERE doctype IN ('CAS', 'CRS') GROUP BY sfcode) AS d ON a.sfcode = d.sfcode LEFT JOIN 

(SELECT sfcode, AVG(unitprice) AS price FROM transactions WHERE doctype IN ('FP', 'LP') GROUP BY sfcode) AS e ON a.sfcode = e.sfcode ORDER BY sfcode;

The last 2 lines of the query is where I need to limit the records in descending order of date before the price is averaged

I have searched for this and found http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/ where I am able to get limited rows but I don't know how to add the doc_type clause and get results based on desc date.

Link to sqlfiddle http://sqlfiddle.com/#!2/4778b/1

I want the result to look like this.. when the limit is set to 3:

| sfcode | stock | lprice | sprice | cprice |
|    1   |   40  | 15.000 | 0.000  | 9.667  |
|    2   |   80  | 25.000 | 0.000  | 19.667 |
|    3   |  120  | 35.000 | 0.000  | 29.66  |
|    4   |  160  | 45.000 | 0.000  | 39.667 |
|    5   |  200  | 55.000 | 0.000  | 49.667 |
|    6   |   0   | 65.000 | 0.000  | 0.000  |
|    7   |   0   | 75.000 | 0.000  | 0.000  |
|    8   |   0   | 85.000 | 0.000  | 0.000  |
|    9   |   0   | 95.000 | 0.000  | 0.000  |
|   10   |   0   |105.000 | 0.000  | 0.000  |

So based on the link that you provided, you can change your query to

set @row_limit = 3;
set @row_num = 0;
set @code = -1;

SELECT a.sfcode, COALESCE((b.QTY - COALESCE(c.QTY,0)),0) AS currentstock, 
a.lastprice AS lprice, COALESCE(CAST(d.price AS decimal(16,3)),0) AS sprice,
COALESCE(CAST(e.price AS decimal(16,3)),0) AS cprice FROM 
(SELECT sfcode, lastprice FROM products) AS a LEFT JOIN
(SELECT sfcode, SUM(COALESCE(QTY, 0)) AS QTY 
    FROM transactions 
    WHERE doctype IN ('FP','LP','CSR') 
    GROUP BY sfcode) AS b ON a.sfcode = b.sfcode LEFT JOIN
(SELECT sfcode, SUM(QTY) AS QTY 
    FROM transactions 
    WHERE doctype IN ('FPR','LPR','CAS','CRS') 
GROUP BY sfcode) AS c ON a.sfcode = c.sfcode LEFT JOIN 
(SELECT sfcode, AVG(unitprice) AS price 
FROM (SELECT sfcode, unitprice, 
    @row_num := if(@code = sfcode, @row_num + 1, 0) AS rowNumber, 
    @code := sfcode AS code 
    FROM transactions 
    WHERE doctype IN ('CAS', 'CRS') 
    ORDER BY sfcode, docdate DESC) AS f 
WHERE f.rowNumber < @row_limit GROUP BY sfcode) 
AS d ON a.sfcode = d.sfcode 
LEFT JOIN (SELECT sfcode, AVG(unitprice) AS price 
FROM **(SELECT sfcode, unitprice, 
    @row_num := if(@code = sfcode, @row_num + 1, 0) as rowNumber, 
    @code := sfcode AS code 
    FROM transactions 
    WHERE doctype IN ('FP', 'LP') 
    ORDER BY sfcode, docdate DESC) AS g** 
WHERE g.rowNumber < @row_limit GROUP BY sfcode) 
AS e ON a.sfcode = e.sfcode ORDER BY sfcode;

where @row_limit is set to the number of most recent transactions that you wish to collect.

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