公司前段时间碰到如下的报表需求:

查询某个用户购买金额最大的前三条记录,如下:

customer price
A 1000
A 888
A 333
B 12222
B 12000
C 3000
C 2000

然后需要通过SQL将其变成四个字段
   
Customer price1 price2 price3
A        1000   888    333
B        12222  12000
C        3000   2000

这个问题牵涉到两个问题,一个取前N位的SQL,另一个将行记录怎么变成列字段。

第一个问题好解决:

1 select a.customer,a.price,count(b.price) as rn
2 from pt a join pt b on a.customer=b.customer and a.price<=b.price 
3 groupby a.customer,a.price;
结果:
+----------+-------+----+
| customer | price | rn |
+----------+-------+----+
| A        |   333 |  3 |
| A        |   888 |  2 |
| A        |  1000 |  1 |
| B        | 12000 |  2 |
| B        | 12222 |  1 |
| C        |  2000 |  2 |
| C        |  3000 |  1 |
+----------+-------+----+
然后就是将行记录变成列字段,这里采用if判断关键字,对上面的查询结果进行如下操作:

1 select 
2 
3 customer, (if(rn=1,price,'')) as price1, (if(rn=2,price,'')) as price2, 
4 
5 (if(rn=3,price,'')) as price3 from a;

执行结果如下所示:
+----------+--------+--------+--------+
| customer | price1 | price2 | price3 |
+----------+--------+--------+--------+
| A        | 143.20 |        |        |
| A        |        | 99.99  |        |
| A        |        |        | 49.99  |
| B        | 63.92  |        |        |
| B        |        | 33.99  |        |
| C        | 99.99  |        |        |
| C        |        | 24.10  |        |
+----------+--------+--------+--------+
针对这个执行结果执行如下的sql既可以得到我们期望的结果了:

select customer,
max(if(rn=1,price,'')) as price1,
max(if(rn=2,price,'')) as price2,
max(if(rn=3,price,'')) as price3
from (
select a.customer,a.price,count(b.price) as rn
from pt a join pt b on a.customer=b.customer and a.price<=b.price 
groupby a.customer,a.price )k
groupby customer;

+----------+--------+--------+--------+
| customer | price1 | price2 | price3 |
+----------+--------+--------+--------+
| A |1000 |888 |333 |
| B |12222 |12000 | |
| C |3000 |2000 | |
+----------+--------+--------+--------+


上面的记录中,价格没有重复的情况,如果有重复的,那么上面的结果方案是不行的,下面是一个办法:

1
 createtable pt(customer varchar(19),price int);
 2 insert pt select  
 3 'A',1000 union all select 
 4 'A',1000 union all select
 5 'A', 888 union all select 
 6 'A',333 union all select 
 7 'B'12222 union all select 
 8 'B'12000 union all select 
 9 'C'3000 union all select 
10 'C'2000;
11 
12 set@n=0;
13 createtable kos select*,@n:=@n+1as id from pt; --建立个辅助表
14 
15 select customer,
16 max(if(rn=1,price,'')) as price1,
17 max(if(rn=2,price,'')) as price2,
18 max(if(rn=3,price,'')) as price3,
19 from (
20 select a.customer,a.price,a.id,count(b.id) as rn
21 from kos a join kos b on a.customer=b.customer and a.id>=b.id
22 groupby a.customer,a.price,a.id )k
23 groupby customer;
执行结果如下:

+----------+--------+--------+--------+--------+
| customer | price1 | price2 | price3 | price4 |
+----------+--------+------+--------+------+
| A |1000 |1000 |888 |333 |
| B |12222 |12000 | | |
| C |3000 |2000 | | |
+----------+--------+--------+--------+------+