公司前段时间碰到如下的报表需求:
查询某个用户购买金额最大的前三条记录,如下:
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,另一个将行记录怎么变成列字段。
第一个问题好解决:
执行结果如下所示:
查询某个用户购买金额最大的前三条记录,如下:
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;
2 from pt a join pt b on a.customer = b.customer and a.price <= b.price
3 groupby a.customer,a.price;
结果:然后就是将行记录变成列字段,这里采用if判断关键字,对上面的查询结果进行如下操作:
+----------+-------+----+
| customer | price | rn |
+----------+-------+----+
| A | 333 | 3 |
| A | 888 | 2 |
| A | 1000 | 1 |
| B | 12000 | 2 |
| B | 12222 | 1 |
| C | 2000 | 2 |
| C | 3000 | 1 |
+----------+-------+----+
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;
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;
执行结果如下所示:
+----------+--------+--------+--------+针对这个执行结果执行如下的sql既可以得到我们期望的结果了:
| 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 | |
+----------+--------+--------+--------+
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;
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 + 1 as 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;
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 + 1 as 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 | | |
+----------+--------+--------+--------+------+