SUM TOP 3(针对每个用户的类型)和TOP 1(针对另一种类型)

时间:2019-06-10 19:12:02

标签: sql

我一直试图编写一个SQL查询,以选择每个用户每种类型的前3名,然后与每种用户另一种类型的前1名求和。如果听起来很复杂,我深表歉意,但我想不出更好的方式来形容它。该查询必须与MySQL 5.x兼容。

我一直在尝试适应以前的查询,但并不高兴。当前已设置为每位用户返回每种类型的前5行,每隔一行将其值1对待。我试图更改一些子句以产生期望的效果,而不会感到高兴。

SELECT
 wsf_ref
,sum(wsf_value) as total
from (select
*,
( select count(*)
 from individual u
 where
   t.wsf_ref = u.wsf_ref and
   t.type = u.type and
   t.wsf_value <= u.wsf_value
) as number
from individual t) t
where (number <= 3 and type <> 'blue' and status = 'Approved' and wsf_progress IN ('Day 1', 'Day 2', 'Day 3'))
or (number = 1 and type = 'blue' and status = 'Approved' and wsf_progress IN ('Day 1', 'Day 2', 'Day 3'))
group by wsf_ref
order by total desc  

Example Data
-------------------------------
id     wsf_ref   status     type       wsf_progress   wsf_value
1      001       Approved       orange     Day 1          5
2      001       Approved       orange     Day 1          10  *
3      001       Approved       orange     Day 1          20  *
4      001       Approved       orange     Day 1          10  *
5      001       Approved       blue       Day 1          10 
6      001       Approved       blue       Day 1          25  * 
7      002       Approved       red        Day 1          10
8      002       Approved       red        Day 1          20  *
9      002       Approved       red        Day 1          30  *
10     002       Approved       red        Day 1          20  *
11     002       Approved       orange     Day 1          10
12     002       Approved       orange     Day 1          20  *
13     002       Approved       orange     Day 1          15  *
14     002       Approved       orange     Day 1          40  *
15     002       Approved       blue       Day 1          20
16     002       Approved       blue       Day 1          35
17     002       Approved       blue       Day 1          50  *

* denotes rows to be summed in the example.

在此示例中,“蓝色”的类型仅是TOP 1。在此示例中,“状态”和“进度”并不是真正相关的,但我希望将它们作为WHERE标准。

Expected Results
----------------------
wsf_ref     total
002         195
001         65

1 个答案:

答案 0 :(得分:1)

您可以通过将row_number()wsf_reftype的分区一起使用来实现。然后在where中,我指定了应该对哪些记录求和(blue的前1个和for other types的前3个)。如果您想按wsf_status来拟合数据,则可以在cte中进行修改。

with cte as (
select
    *
    ,ROW_NUMBER() over (partition by wsf_ref, type order by wsf_value desc) as number
from individual
--where wsf_status <your condition>
)
select
     wsf_ref
    ,sum(wsf_value) as total
from cte
where (number <= 3 and type <> 'blue')
or (number = 1 and type = 'blue')
group by wsf_ref

没有row_number()的解决方案。

select
     wsf_ref
    ,sum(wsf_value) as total
from (select
  *,
  ( select count (*)
     from individual u
     where
       t.wsf_ref = u.wsf_ref and
       t.type = u.type and
       t.wsf_value <= u.wsf_value
  ) as number
from individual t) t
where (number <= 3 and type <> 'blue')
or (number = 1 and type = 'blue')
group by wsf_ref

有其他条件(这很丑,因为在此版本的mysql中我们无法使用窗口函数)

select
     wsf_ref
    ,sum(wsf_value) as total
from (select
  *,
  ( select count (*)
     from (select * from individual where wsf_status = 'Approved' and wsf_progress IN ('Day 1', 'Day 2', 'Day 3')) u
     where
       t.wsf_ref = u.wsf_ref and
       t.type = u.type and
       t.wsf_value <= u.wsf_value
  ) as number
from (select * from individual where wsf_status = 'Approved' and wsf_progress IN ('Day 1', 'Day 2', 'Day 3')) t) t
where (number <= 3 and type <> 'blue')
or (number = 1 and type = 'blue')
group by wsf_ref