开发者

Group By specified numbers of ordered rows

开发者 https://www.devze.com 2023-03-27 03:01 出处:网络
I have such table in my MySQL database: --------------------------- |fid | price | date| ---------------------------

I have such table in my MySQL database:

---------------------------
|fid | price | date       |
---------------------------
|  1 | 1.23  | 2开发者_JAVA技巧011-08-11 |
|  1 | 1.43  | 2011-08-12 |
|  1 | 1.54  | 2011-08-13 |
|  1 | 1.29  | 2011-08-14 |
|  1 | 1.60  | 2011-08-15 |
|  1 | 1.80  | 2011-08-16 |

fid - this is the product id

price - this is the price of the product in specified day

I want to calculate average price of the product fid=1. I want to calculate the average price of first n=3 rows ordered by date for specified fid, and then calculate average price for another 3 rows ordered by date.

How can I group first 3 rows and calculate avg and then group next 3 rows and calculate avg. Before calculation I need to sort the rows by date and then group n rows.

If n=3 this should return such result:

--------------
|fid | price |
--------------
|  1 | 1.40  | 2011-08-11 -> 2011-08-13 - average price for 3 days
|  1 | 1.56  | 2011-08-14 -> 2011-08-16 - average price for 3 days

How can I create SQL Query to do such calculations?

Thanks in advance.


Unluckily mysql doesn't offer analytic functions like oracle,mssql and postgres do. So you have to play with variables to reach your goal.

create table mytest (
id int not null auto_increment primary key,
fid int,
price decimal(4,2),
fdate date
) engine = myisam;

insert into mytest (fid,price,fdate)
values 
(1,1.23,'2011-08-11'),
(1,1.43,'2011-08-12'),
(1,1.54,'2011-08-13'),
(1,1.29,'2011-08-14'),
(1,1.60,'2011-08-15'),
(1,1.80,'2011-08-16');


select 
concat_ws('/',min(fdate),max(fdate)) as rng,
format(avg(price),2) as average from (
select *,@riga:=@riga+1 as riga
    from mytest,(select @riga:=0) as r order by fdate
     ) as t
group by ceil(riga/3);


+-----------------------+---------+
| rng                   | average |
+-----------------------+---------+
| 2011-08-11/2011-08-13 | 1.40    |
| 2011-08-14/2011-08-16 | 1.56    |
+-----------------------+---------+
2 rows in set (0.02 sec)


maybe you could use

GROUP BY FLOOR(UNIX_TIMESTAMP(date)/(60*60*24*3))

= convert to secounds, divide by secounds for 3 days, and round down


SELECT AVG( price ) FROM my_table
    GROUP BY ( date - ( SELECT MIN( date ) FROM my_table WHERE fid = 1 ) ) DIV 3
    WHERE fid = 1


select fid, avg(price), min(date), max(date)
from
    (select floor((@rownum := @rownum + 1)/3) as `rank`,  prices.*
    from prices, (SELECT @rownum:=-1) as r
    order by date) as t
group by rank
0

精彩评论

暂无评论...
验证码 换一张
取 消