id的前20% - MySQL

时间:2016-07-20 21:29:26

标签: mysql

我在这里使用的修改版本的查询与其他问题类似:Convert SQL Server query to MySQL

Select *
from
(
SELECT tbl.*, @counter := @counter +1 counter
FROM (select @counter:=0) initvar, tbl
Where client_id = 55
ORDER BY ordcolumn
) X
where counter >= (80/100 * @counter);
ORDER BY ordcolumn

tbl。*包含字段' client_id'我试图在一个语句中获取每个client_id的前20%的记录。现在,如果我在where语句中为它提供单个client_id,它会给我正确的结果,但是如果我将它提供给多个client_id,它只需要占用组合记录集的前20%而不是单独执行每个client_id。 / p>

我知道如何在大多数数据库中执行此操作,但MySQL中的逻辑正在逃避我。我感觉它涉及一些排名和分区。

样本数据非常简单。

Client_id  rate    
1          1
1          2
1          3
(etc to rate = 100)
2          1
2          2
2          3
(etc to rate = 100)

实际值不是干净的,但是有效。

作为额外奖励......还有一个与这些记录相关联的日期字段,此客户端存在1到100个多个日期。我需要为每个client_id,年(日期),月(日期)

获取前20%的记录

2 个答案:

答案 0 :(得分:2)

您需要为每个客户端执行枚举:

SELECT *
FROM (SELECT tbl.*, @counter := @counter +1 counter
             (@rn := if(@c = client_id, @rn + 1,
                        if(@c := client_id, 1, 1)
                       )
             )
      FROM (select @c := -1, @rn := 0) initvar CROSS JOIN tbl
      ORDER BY client_id, ordcolumn
     ) t cross join
     (SELECT client_id, COUNT(*) as cnt
      FROM tbl
      GROUP BY client_id
     ) tt
where rn >= (80/100 * tt.cnt);
ORDER BY ordcolumn;

答案 1 :(得分:1)

以戈登的答案为出发点,我认为这可能更接近你的需要。

SELECT t.*
    , (@counter := @counter+1) AS overallRow
    , (@clientRow := if(@prevClient = t.client_id, @clientRow + 1,
                if(@prevClient := t.client_id, 1, 1) -- This just updates @prevClient without creating an extra field, though it makes it a little harder to read
               )
     ) AS clientRow
    -- Alteratively (for everything done in clientRow)
    , @clientRow := if(@prevClient = t.client_id, @clientRow + 1, 1) AS clientRow
    , @prevClient := t.client_id AS extraField
    -- This may be more reliable as well; I not sure if the order 
    -- of evaluation of IF(,,) is reliable enough to guarantee
    -- no side effects in the non-"alternatively" clientRow calculation.
FROM tbl AS t
INNER JOIN (
    SELECT client_id, COUNT(*) AS c
    FROM tbl 
    GROUP BY client_id
   ) AS cc ON tbl.client_id = cc.client_id
INNER JOIN (select @prevClient := -1, @clientRow := 0) AS initvar ON 1 = 1
WHERE t.client_id = 55
HAVING clientRow * 5 < cc.c  -- You can use a HAVING without a GROUP BY in MySQL 
     -- (note that clientRow is derived, so you cannot use it in the `WHERE`)
ORDER BY t.client_id, t.ordcolumn
;