当 LIMIT 值来自 Mysql 中的子查询时,如何仅查看 table 的一部分

How to view only a portion of the table when the LIMIT value is derived from a subquery in Mysql

对于table'Issue'

-

Call_ref 是唯一标识每个调用的唯一键。每次调用均由用户发出,用户通过 caller_id 标识。每个用户可以拨打多个电话,但每个电话只有一个 caller_id。我想显示前 20% 的活跃用户拨打的电话。 我试过这个查询-

SELECT Caller_id, COUNT(Call_ref) FROM Issue
GROUP BY Caller_id 
ORDER BY COUNT(Call_ref) 
LIMIT round(COUNT(distinct Caller_id)/5)

但是,LIMIT 似乎只接受数字。有没有一种方法可以将此视图限制为结果 table?

中所有记录的前 20%

如果您使用的是 运行 MySQL 8.0,则可以使用 window 函数执行此操作。根据您当前的查询,那将是:

select *
from (
    select caller_id, count(*) , percent_rank() over(order by count(*) desc) prn
    from issue
    group by caller_id 
) t
where prn < 0.2

可以使用动态sql

SELECT CONCAT('SELECT Caller_id, COUNT(Call_ref) FROM Issue
GROUP BY Caller_id 
ORDER BY COUNT(Call_ref) 
LIMIT ',round(COUNT(distinct Caller_id)/5)) into @sql FROM Caller_id;
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;

试试这个代码

SET @row_number = 0;
SET @rows = (select count(distinct Caller_id) from Issue)/5;
select Caller_id, _counter  from ( SELECT (@row_number:=@row_number + 1) AS num ,  Caller_id, COUNT(_counter) cnt FROM Issue
GROUP BY Caller_id  FROM  Issue ) x where num < @rows
order by _counter

用window函数可以做到,但是GMB的解是错误的(证明:db<>fiddle link)。很遗憾,我不能发表评论。

这是我的解决方案:

CREATE TABLE ranked (
SELECT
  a.caller_id
  ,a.count_calls
  ,RANK() OVER w AS 'ranked'
  ,ROW_NUMBER() OVER w AS 'row_num'
FROM
  (
  SELECT
    caller_id
    ,COUNT(*) count_calls
  FROM
        issue
  GROUP BY 1
    ORDER BY 2 DESC
    ) a
WINDOW w AS (ORDER BY count_calls DESC)
);

CREATE TABLE max_row_num (
SELECT MAX(row_num) AS max_row_num FROM ranked
);

CREATE TABLE result (
SELECT
  c.*
FROM
  issue c
  INNER JOIN
  (
    SELECT
    a.Caller_Id
    ,a.count_calls
    FROM
    ranked a
    INNER JOIN (SELECT (max_row_num * 20 /100)per FROM max_row_num) b
    WHERE
    a.ranked <= b.per        
    ) d ON (c.Caller_id = d.Caller_id)  
)

SELECT * FROM result;

解决方案:db<>fiddle link

具有 ROW_NUMBER()COUNT(*) window 函数:

SELECT Caller_id, Counter
FROM (
  SELECT Caller_id, COUNT(*) Counter,
         ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) rn,
         COUNT(*) OVER () total
  FROM Issue
  GROUP BY Caller_id 
) t
WHERE rn / total <= 0.2
ORDER BY rn