Mysql 计算用户通过sql看到的唯一项

Mysql 计算用户通过sql看到的唯一项,mysql,sql,Mysql,Sql,我需要帮助来解决下一个案子 用户希望查看的数据可通过分页请求访问,稍后这些请求将以下一种形式存储在数据库中: +----+---------+-------+--------+ | id | user id | first | amount | +----+---------+-------+--------+ | 1 | 1 | 0 | 5 | | 2 | 1 | 10 | 10 | | 3 | 1 | 10 |

我需要帮助来解决下一个案子

用户希望查看的数据可通过分页请求访问,稍后这些请求将以下一种形式存储在数据库中:

+----+---------+-------+--------+
| id | user id | first | amount |
+----+---------+-------+--------+
|  1 |    1    |   0   |    5   |
|  2 |    1    |   10  |   10   |
|  3 |    1    |   10  |    5   |
|  4 |    1    |   15  |   10   |
|  5 |    2    |   0   |   10   |
|  6 |    2    |   0   |    5   |
|  7 |    2    |   10  |    5   |
+----+---------+-------+--------+
该表按用户id asc、第一个asc、金额描述排序

任务是编写SQL语句,计算用户看到的唯一数据总量

对于第一个用户,总金额必须为20,因为id=1的请求返回了前5项,id=2的请求返回了另外10项。id=3的请求返回id=2的请求已经“看到”的数据。id=4的请求与id=2的请求相交,但仍返回5条“未看到”的数据

对于第二个用户,总金额必须为15

作为SQL语句的结果,我应该得到下一个输出:

+---------+-------+
| user id | total |
+---------+-------+
|    1    |   20  |
+---------+-------+
|    2    |   15  |
+---------+-------+

我使用的是MySQL 5.7,所以窗口函数对我来说不可用。我已经做了一天的这项工作,但仍然无法达到预期的效果。如果此设置不可行,我将在应用程序代码中计算结果。我将感谢任何建议或帮助解决这项任务,谢谢

这是一种缺口和孤岛问题。在这种情况下,使用累计最大值确定一个请求是否与前一个请求相交。如果不是,那就是相邻请求孤岛的开始。初始值的累积和分配一个岛,然后聚合计算每个岛

所以,这些岛屿看起来像这样:

select userid, min(first), max(first + amount) as last
from (select t.*,
             sum(case when prev_last >= first then 0 else 1 end) over
                 (partition by userid order by first) as grp
      from (select t.*,
                   max(first + amount) over (partition by userid order by first range between unbounded preceding and 1 preceding) as prev_last
            from t
           ) t
     ) t
group by userid, grp;
然后,您希望通过userid对其进行汇总,这是一个更高级别的聚合:

with islands as (
      select userid, min(first) as first, max(first + amount) as last
      from (select t.*,
                   sum(case when prev_last >= first then 0 else 1 end) over
                       (partition by userid order by first) as grp
            from (select t.*,
                         max(first + amount) over (partition by userid order by first range between unbounded preceding and 1 preceding) as prev_last
                  from t
                 ) t
           ) t
      group by userid, grp
     )
select userid, sum(last - first) as total
from islands
group by userid;

是一个dbfiddle。

此逻辑与Gordon的类似,但也运行在MySQL的旧版本上

select userid
  -- overall length minus gaps
  ,max(maxlast)-min(minfirst) + sum(gaplen) as total
from
 ( 
   select userid
     ,prevlast
     ,min(first) as minfirst -- first of group
     ,max(last) as maxlast   -- last of group
      -- if there was a gap, calculate length of gap
     ,min(case when prevlast < first then prevlast - first else 0 end) as gaplen
   from
    (
      select t.*
        ,first + amount as last -- last value in range
        ,( -- maximum end of all previous rows
           select max(first + amount) 
           from t as t2
           where t2.userid = t.userid
             and t2.first < t.first
         ) as prevlast
      from t 
    ) as dt
   group by userid, prevlast
 ) as dt
group by userid
order by userid

请参阅

谢谢您的详细解释,我会考虑更新环境来使用MySQL 8.谢谢,这就是MySQL 5.7所需要的。