【问题标题】:SQL subquery in SELECT clauseSELECT 子句中的 SQL 子查询
【发布时间】:2021-06-05 22:02:52
【问题描述】:

我正在尝试查找过去 30 天内的管理员活动。

accounts 表存储用户数据(用户名、密码等)

每天结束时,如果用户已登录,它将在 player_history 表中创建一个包含更新数据的新条目。这样我们就可以随着时间的推移跟踪进度。

帐户表:

id username admin
1 Michael 4
2 Steve 3
3 Louise 3
4 Joe 0
5 Amy 1

player_history 表:

id user_id created_at playtime
0 1 2021-04-03 10
1 2 2021-04-04 10
2 3 2021-04-05 15
3 4 2021-04-10 20
4 5 2021-04-11 20
5 1 2021-05-12 40
6 2 2021-05-13 55
7 3 2021-05-17 65
8 4 2021-05-19 75
9 5 2021-05-23 30
10 1 2021-06-01 60
11 2 2021-06-02 65
12 3 2021-06-02 67
13 4 2021-06-03 90

以下查询

SELECT a.`username`, SEC_TO_TIME((MAX(h.`playtime`) - MIN(h.`playtime`))*60) as 'time' FROM `player_history` h, `accounts` a WHERE h.`created_at` > '2021-05-06' AND h.`user_id` = a.`id` AND a.`admin` > 0 GROUP BY h.`user_id`

输出此表:

请注意,这只是管理员活动,因此 Joe 不包含在此数据中。

从 2021-05-06 至今 (yy-mm-dd):

username time
Michael 00:20:00
Steve 00:10:00
Louise 00:02:00
Amy 00:00:00

从数据中可以看出,Amy 的时间显示为 0,尽管她在上个月玩了 10 分钟。这是因为她从 2021-05-06 开始只有 1 个条目,因此没有可比较的数据。它是 0,因为 10-10 = 0。

另一个缺陷是它不包括上个月的所有活动,基本上只是从最低值中减去最高值。

因此,我尝试通过将 2021-05-06 之后的最高值与他们在该日期之前的最近一次登录进行比较来解决此问题。所以我稍微修改了一下查询:

SELECT a.`Username`, SEC_TO_TIME((MAX(h.`playtime`) - (SELECT MAX(`playtime`) FROM `player_history` WHERE a.`id` = `user_id` AND `created_at` < '2021-05-06'))*60) as 'Time' FROM `player_history` h, `accounts` a WHERE h.`created_at` >= '2021-05-06' AND h.`user_id` = a.`id` AND a.`admin` > 0 GROUP BY h.`user_id`

所以现在它会输出:

username time
Michael 00:50:00
Steve 00:50:00
Louise 00:52:00
Amy 00:10:00

但我觉得整个查询效率很低。有没有更好的方法来做到这一点?

【问题讨论】:

  • 这段代码存在 很多 缺陷,首先是因为selectgroup by 不一致,所以它在语法上不正确。我建议您提供示例数据、期望的结果以及对您想要完成的目标的清晰说明。
  • 我已经编辑了@GordonLinoff 的原帖
  • 我已经编辑了我的原始帖子? @草莓
  • 是的。我们可以看到。

标签: mysql sql subquery correlated


【解决方案1】:

我想你想要lag():

SELECT a.username,
       SEC_TO_TIME(SUM(h.playtime - COALESCE(h.prev_playtime, 0))) as time
FROM accounts a JOIN
     (SELECT h.*,
             LAG(playtime) OVER (PARTITION BY u.user_id ORDER BY h.created_at) as prev_playtime
      FROM player_history h
     ) h
     ON h.user_id = a.id
WHERE h.created_at > '2021-05-06' AND
      a.admin > 0
GROUP BY a.username;

除了LAG() 逻辑,请注意查询的其他更改:

  • 使用正确、明确、标准、可读的JOIN语法。
  • SELECTGROUP BY 使用一致的列。
  • 删除列别名周围的单引号。
  • 删除反引号;它们只会使查询变得杂乱无章,使书写和阅读变得更加困难。

【讨论】:

  • 这非常有效!非常感谢。很好的解释。
  • 只是好奇,这花了你多长时间?
猜你喜欢
  • 2014-02-23
  • 2015-08-02
  • 1970-01-01
  • 2012-02-14
  • 2021-11-16
  • 1970-01-01
  • 2019-09-15
  • 1970-01-01
相关资源
最近更新 更多