MySQL查询问题。每种类型的总排名前3名,按组的排名前1名

时间:2019-06-12 20:46:38

标签: mysql 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  

示例数据

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

Current Results
----------------------
wsf_ref     total
002         120
001         45

似乎只为每种类型选择前1个,而忽略数字<= 3子句。

1 个答案:

答案 0 :(得分:1)

SQL DEMO

首先使用用户变量,您需要创建一个rn以获得typeref的前3名

SELECT t.*, @rn := if(  @ref = `wsf_ref`,
                       if ( @type = `type`, 
                             @rn + 1,
                             if( @type := `type`, 1, 1)                     
                           ),
                       if ( (@ref := `wsf_ref`) or (@type := `type`), 1, 1)
                    ) as rn,
            @type,
            @ref
FROM t
CROSS JOIN ( SELECT @rn := 0, @type := '', @ref := '') as var
ORDER BY `wsf_ref`, `type`, `wsf_value` DESC ;

部分结果

| id | wsf_ref |   status |   type | wsf_progress | wsf_value | rn |  @type | @ref |
|----|---------|----------|--------|--------------|-----------|----|--------|------|
|  6 |       1 | Approved |   blue |        Day 1 |        25 |  1 |   blue |    1 |
|  5 |       1 | Approved |   blue |        Day 1 |        10 |  2 |   blue |    1 |
|  3 |       1 | Approved | orange |        Day 1 |        20 |  1 | orange |    1 |
|  2 |       1 | Approved | orange |        Day 1 |        10 |  2 | orange |    1 |
|  4 |       1 | Approved | orange |        Day 1 |        10 |  3 | orange |    1 |
|  1 |       1 | Approved | orange |        Day 1 |         5 |  4 | orange |    1 |
| 17 |       2 | Approved |   blue |        Day 1 |        50 |  1 |   blue |    2 |
| 16 |       2 | Approved |   blue |        Day 1 |        35 |  2 |   blue |    2 |
| 15 |       2 | Approved |   blue |        Day 1 |        20 |  3 |   blue |    2 |
| 14 |       2 | Approved | orange |        Day 1 |        40 |  1 | orange |    2 |
| 12 |       2 | Approved | orange |        Day 1 |        20 |  2 | orange |    2 |
| 13 |       2 | Approved | orange |        Day 1 |        15 |  3 | orange |    2 |
| 11 |       2 | Approved | orange |        Day 1 |        10 |  4 | orange |    2 |
|  9 |       2 | Approved |    red |        Day 1 |        30 |  1 |    red |    2 |
| 10 |       2 | Approved |    red |        Day 1 |        20 |  2 |    red |    2 |
|  8 |       2 | Approved |    red |        Day 1 |        20 |  3 |    red |    2 |
|  7 |       2 | Approved |    red |        Day 1 |        10 |  4 |    red |    2 |

然后使用条件SUM

SELECT wsf_ref, SUM( CASE WHEN type = 'blue' and rn = 1 
                          THEN `wsf_value`
                          WHEN type <> 'blue' and rn in (1,2,3)
                          THEN `wsf_value`
                          ELSE 0
                     END
                   ) as sum_total
FROM ( 
        SELECT t.*, @rn := if(  @ref = `wsf_ref`,
                               if ( @type = `type`, 
                                     @rn + 1,
                                     if( @type := `type`, 1, 1)                     
                                   ),
                               if ( (@ref := `wsf_ref`) and (@type := `type`), 1, 1)
                            ) as rn,
                    @type,
                    @ref
        FROM t
        CROSS JOIN ( SELECT @rn := 0, @type := '', @ref := '') as var
        ORDER BY `wsf_ref`, `type`, `wsf_value` DESC   
     ) t
GROUP BY `wsf_ref

输出

| wsf_ref | sum_total |
|---------|-----------|
|       1 |        65 |
|       2 |       195 |

编辑:

询问了一下之后,我得到了一个简单的版本:

What boolean value return assign integer or string to a variable

DEMO

SELECT t.*,
       (@rn := if(@tr = CONCAT_WS(':', wsf_ref, type),
                  @rn + 1,
                  if(@tr := CONCAT_WS(':', wsf_ref, type), 1, 1
                    )                     
                 )
       ) as rn
FROM (SELECT t.*
      FROM t 
      ORDER BY `wsf_ref`, `type`, `wsf_value` DESC
     ) t CROSS JOIN
     (SELECT @rn := 0, @tr := '') params;