【问题标题】:mysql - getting only the results with diferences from same tablemysql - 仅获取来自同一张表的差异的结果
【发布时间】:2014-07-17 00:46:05
【问题描述】:

所以我有一个表格,里面有一个分数系统。它看起来沿着这条线:

列:

ID  Name    Date        Points
1   Peter   2014-07-15  5
2   John    2014-07-15  6
3   Bill    2014-07-15  3

等等……

每天都会将新结果放入表格中,并累积总积分,但是为了能够获得历史值,将结果放入新行中。所以在 2014-07-16,表格将如下所示:

ID  Name    Date        Points
1   Peter   2014-07-15  5
2   John    2014-07-15  6
3   Bill    2014-07-15  3
4   Peter   2014-07-16  11
5   John    2014-07-16  12
6   Bill    2014-07-16  3

但是有时候当玩家一整天没有参加并且没有获得任何积分时,他仍然会被添加,但积分会保持不变(这里以比尔)

我的问题是如何计算每种类型玩家的数量 (活跃 - 彼得和约翰,即当积分值从一个日期更改为另一个日期和不活跃 - 比尔,即当点值保持不变)

我设法让这个查询只选择具有相同价值的球员,但它给了我球员名单而不是人数。虽然我可能对这个查询有误:

SELECT Points, name, COUNT(*)
FROM points
WHERE DATE(Date) = '2014-07-15' OR DATE(Date) = '2014-07-16'
GROUP BY Points
HAVING COUNT(*)>1

我不知道如何计算行数(可以使用 PHP 绕过技巧来获取行数,但只对 SQL 感兴趣)或如何反转它,以获取拥有不同的分数(同样,可以获得总行数,然后减去上述数字,但对此也不感兴趣 - 我更喜欢 SQL)。

提前致谢。

【问题讨论】:

    标签: php mysql sql count


    【解决方案1】:

    你已经很接近了。

    如果每个“日期”每个“玩家”最多有一行,则可以执行以下操作:

    SELECT SUM(IF(c.cnt_distinct_points<2,1,0)) AS cnt_inactive
         , SUM(IF(c.cnt_distinct_points>1,1,0)) AS cnt_active 
      FROM ( SELECT p.name
                  , COUNT(DISTINCT p.points) AS cnt_distinct_points
               FROM points p
              WHERE DATE(p.Date) IN ('2014-07-15','2014-07-16')
              GROUP BY p.name
           ) c
    

    内联视图查询(别名为 c)获取每个玩家的不同“点数”值的计数。我们需要对名字进行“分组”,这样我们就可以获得一个不同的玩家列表,以及分数值是否不同的指示。如果给定玩家的所有非空“点”值都相同,COUNT(DISTINCT ) 将返回值 1。否则,我们将得到大于 1 的值。

    外部查询处理该列表,将所有行折叠成一行。 “技巧”是在 SELECT 列表中使用返回 1 或 0 的表达式,具体取决于玩家是否“不活动”,并对其执行 SUM 聚合。执行相同的操作,但如果玩家“活跃”,则使用不同的表达式返回 1。

    如果一个玩家的不同点数为 1,我们实际上将在cnt_inactive 上加 1。同样,如果玩家的不同点大于 1,我们将在 cnt_active 上加 1。

    如果这没有意义,如果您有任何问题,请告诉我。


    注意:理想情况下,我们会避免在 p.Date 列引用周围使用 DATE() 函数,因此我们可以启用适当的索引。

    如果Date 列定义为(MySQL 数据类型)DATE,则不需要DATE() 函数。如果Date 列定义为(MySQL 数据类型)DATETIMETIMESTAMP,我们可以使用等效谓词:

    WHERE p.Date >= '2014-07-15' AND p.Date < '2014-07-16' + INTERVAL 1 DAY
    

    这看起来更复杂,但这种形式的谓词是 sargable(即 MySQL 可以使用索引范围扫描来满足它,而不必查看表中的每一行。)

    为了提高性能,我们可能会受益于具有namedate 前导列的索引

    ... ON points (`name`,`date`)
    

    (MySQL 可能能够避免GROUP BY 的“使用文件排序”操作)。

    【讨论】:

    • 非常感谢您提供非常具体的答案。我不得不说有关 Date 函数的附加信息对性能非常有帮助。
    【解决方案2】:

    我会通过查看之前的点数然后进行比较来解决这个问题:

    select date(date), count(*) as NumActives;
    from (select p.*,
                 (select p2.points
                  from points p2
                  where p2.name = p.name and p2.date < p.date
                  order by p2.date desc
                  limit 1
                 ) as prev_points
          from points p
         ) p
    where prev_points is NULL or prev_points <> points;
    

    当然,您可以添加 where 子句来获取任何特定日期的计数。

    【讨论】:

    • 你的回答似乎也不错,但我最终还是继续回答 @spencer7593
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多