MySQL查询问题。根据参考,每种类型前3名和每组前1名的总和

MySQL查询问题。根据参考,每种类型前3名和每组前1名的总和,mysql,sql,Mysql,Sql,我一直在尝试编写一个SQL查询,以选择每个用户每种类型的前3名,并与每个用户另一种类型的前1名相加。如果听起来很复杂,我道歉,但我想不出更好的方式来描述它。该查询必须与MySQL 5.x兼容 我一直在毫无乐趣地尝试适应之前的一个问题。目前已将其设置为每个用户返回每个类型的前5行,并将其他每行视为值1。我试图修改一些条款,以产生预期的效果,但毫无乐趣 SELECT wsf_ref ,sum(wsf_value) as total from (select *, ( select count(*)

我一直在尝试编写一个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  
在本例中,“蓝色”的类型仅为顶部1。“状态”和“进度”在本例中并不真正相关,但我希望将它们作为WHERE标准包括在内

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

Current Results
----------------------
wsf_ref     total
002         120
001         45
看起来它只是为每种类型选择了前1名,而忽略了数字

首先,对于用户变量,您需要创建一个rn,以便为每个
类型
ref

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
编辑:

在四处询问之后,我得到了一个更简单的版本:

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;

为什么蓝色是第一名?请解释一下对我没有帮助的逻辑@strawberry对不起,我需要(每种类型前3个wsf_值,其中类型!=blue)+(每种类型前1个wsf_值,其中类型=blue)按wsf_ref分组。你能相应地编辑这个问题吗?如果你说前3个为什么002有7行标记为sum?几乎在那里,但实际上它似乎也是对重复项求和,它为第一种类型添加了一个额外的行。所以对于橙色,rn是1,1,2,3,而不是1,2,3,4。那一行的@type也是空的。只有第一行是空的,所以非常接近。你说的额外一行是什么意思?我得到了你想要的结果,我今晚会公布结果。与您提供的代码相同,在dB fiddle中运行良好,但在我的服务器上通过PHP执行操作时,它会添加一行额外的内容。它选择了前3个代表红色,前1个代表蓝色,这是正确的。然而,橙色有四行。有两个橙色的rn=1,但其中一个@type为空,另一个为橙色。莫名其妙!好的,不要使用PHP在测试中添加其他层,直接在mysql上测试它。我真的不知道两个橙色的rn=1会是什么样子。我将等待你的答复。尝试更改sqlfiddle中的数据,以便我可以复制它。
| wsf_ref | sum_total |
|---------|-----------|
|       1 |        65 |
|       2 |       195 |
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;