【问题标题】:MySQL select after row on specific rulesMySQL 在特定规则的行后选择
【发布时间】:2021-03-03 04:35:55
【问题描述】:

我有一张这样的桌子:

CREATE TABLE IF NOT EXISTS `logging` (
  `id` int(6) unsigned NOT NULL,
  `status` varchar(150) NOT NULL,
  `timestamp` DATETIME NOT NULL,
  PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `logging` (`id`, `status`, `timestamp`) VALUES
  ('1', 'logout', '2021-01-01 05:01:00'),
  ('2', 'login', '2021-01-01 06:02:00'),
  ('3', 'online', '2021-01-01 06:03:00'),
  ('4', 'away', '2021-01-01 06:04:00'),
  ('5', 'online', '2021-01-01 06:05:00'),
  ('6', 'logout', '2021-01-02 04:00:00'),
  ('7', 'login', '2021-01-02 04:05:00'),
  ('8', 'online', '2021-01-02 04:07:00'),
  ('9', 'away', '2021-01-02 04:08:00'),
  ('10', 'break', '2021-01-02 04:10:00'),
  ('11', 'online', '2021-01-02 04:15:00'),
  ('12', 'logout', '2021-01-02 04:55:00'),
  ('13', 'login', '2021-01-02 05:04:00'),
  ('14', 'online', '2021-01-02 05:05:00'),
  ('15', 'away', '2021-01-03 05:01:00'),
  ('16', 'logout', '2021-01-03 05:02:00'),
  ('17', 'login', '2021-01-03 05:04:00'),
  ('18', 'online', '2021-01-03 05:05:00'),
  ('19', 'logout', '2021-01-04 03:05:00'),
  ('20', 'login', '2021-01-04 05:07:00'),
  ('21', 'online', '2021-01-04 06:00:00'),
  ('22', 'logout', '2021-01-05 10:00:00'),
  ('23', 'login', '2021-01-05 11:00:00'),
  ('24', 'away', '2021-01-05 11:01:00'),
  ('25', 'online', '2021-01-06 06:01:00'),
  ('26', 'login', '2021-01-07 06:01:00'),
  ('26', 'logout', '2021-01-07 07:01:00');
id status timestamp
1 logout 2021-01-01 05:01:00
2 login 2021-01-01 06:02:00
3 online 2021-01-01 06:03:00
4 away 2021-01-01 06:04:00
5 online 2021-01-01 06:05:00
6 logout 2021-01-02 04:00:00
7 login 2021-01-02 04:05:00
8 online 2021-01-02 04:07:00
9 logout 2021-01-02 04:55:00

......

上面插入查询中提供的数据。

我想要一个输出:

date A (online) B (Logout)
2021-01-01 2021-01-02 04:07:00 2021-01-02 04:55:00
2021-01-02 2021-01-02 05:05:00 2021-01-03 04:59:59
2021-01-03 2021-01-03 05:05:00 2021-01-04 03:05:00
2021-01-04 2021-01-04 06:00:00 2021-01-04 04:59:59
2021-01-05 2021-01-04 05:00:00 2021-01-05 10:00:00
2021-01-06 2021-01-04 11:00:00 2021-01-06 04:59:59

规则是,1 个日志日是从 5:00:00 到(第二天)04:59:59。 'A' 是从最后一次在线开始的时间戳(登录后,如果有),'B' 是从最后一次注销开始的时间戳(如果没有注销,B 设置为 04:59:59。 另一个规则是,当最后一天在“在线”之后没有“注销”时,它会被计算到下一个日志日(如果最后一个日志日的最后一条记录是 ',则下一个日志日设置为 05.00.00在线')

目前我正在使用此查询来应用日志日规则:

SELECT date(t1.timestamp) dt, (t2.timestamp) A, (t3.timestamp) B, t1.status, t2.status, t3.status
FROM logging t1
JOIN logging t2 ON t1.timestamp < t2.timestamp
JOIN logging t3 ON t2.timestamp < t3.timestamp
WHERE 
t1.status = 'login'
AND t2.status = 'online'
AND t3.status = 'logout'
AND NOT EXISTS ( SELECT NULL
               FROM loggingt4
               WHERE t1.timestamp < t4.timestamp
                 AND t4.timestamp < t2.timestamp
                 AND t4.status IN ('login', 'online', 'logout') )
AND NOT EXISTS ( SELECT NULL
               FROM logging t5
               WHERE t2.timestamp < t5.timestamp
                 AND t5.timestamp < t3.timestamp
                 AND t5.status IN ('login', 'logout'))
AND DATE(t1.timestamp - INTERVAL 6 HOUR) = DATE(t3.timestamp - INTERVAL '05:59:59' HOUR_SECOND);

【问题讨论】:

  • 啊,是的,我的意思是 04:59:59 @Akina
  • 我想要一个输出:所需输出中的值在源数据中不存在。
  • 对不起我的坏..我刚刚更新了源数据@Akina
  • 为什么从'2021-01-01 06:02:00''2021-01-02 04:00:00' 的会话未列在所需的输出中?请仔细验证您的问题及其中的所有值,然后发布。不用急。 PS。 精确 MySQL 版本是什么?
  • 不计算在内,因为我只想计算最后一次“登录”(如果有)之后的最后一次“在线”,因此所需的输出如表中所述。如果在 1 个日志日内没有登录,那么如果最后一天有“在线”行,则设置为 5:00:00,但如果不是,则计算该日志日的第一个“在线”。我'正在使用 MySQL 5.7.24 版。提前感谢@Akina,是的,我刚刚添加了新的源数据,对不起我的匆忙

标签: mysql datetime join sql-timestamp


【解决方案1】:

检查一下:

WITH cte AS (
SELECT DATE(t1.`timestamp` - INTERVAL 5 HOUR) `date`,
       MAX(t1.`timestamp`) login, 
       MAX(t2.`timestamp`) online, 
       MAX(t3.`timestamp`) logout
FROM logging t1
JOIN logging t2 ON t1.`timestamp` < t2.`timestamp`
JOIN logging t3 ON t2.`timestamp` < t3.`timestamp`
WHERE t1.status = 'login'
  AND t2.status = 'online'
  AND t3.status = 'logout'
  AND NOT EXISTS ( SELECT NULL
                   FROM logging t4
                   WHERE t1.`timestamp` < t4.`timestamp`
                     AND t4.`timestamp` < t2.`timestamp`
                     AND t4.status IN ('login', 'online', 'logout') )
  AND NOT EXISTS ( SELECT NULL
                   FROM logging t5
                   WHERE t2.`timestamp` < t5.`timestamp`
                     AND t5.`timestamp` < t3.`timestamp`
                     AND t5.status IN ('login', 'logout') )
GROUP BY `date`
)
SELECT `date`,
       online,
       CASE WHEN DATE(online - INTERVAL 5 HOUR) = DATE(logout - INTERVAL '04:59:59' HOUR_SECOND)
            THEN logout
            ELSE DATE(online + INTERVAL 19 HOUR) + INTERVAL '04:59:59' HOUR_SECOND
            END logout
FROM cte

fiddle

CTE 仅用于可见性 - 您可以将所有内容组合到一个查询中。

【讨论】:

  • 谢谢你,我已经检查过了,几乎完美地解决了我的问题,还有一个问题..如何继续记录到第二天?我的意思是,正如我之前提到的,如果用户保持在线并跨越时间边界然后在 5.02 注销,我想将第二天的日志记录到 5:00:00-05:02:00。如果只有最后一个日志日是“在线”,这将被计算在内..
  • @DianAriefRisdianto 还有一个问题.. 如何继续记录到第二天? 正式会话可以分为 2、3 和更多部分,是吗?查看规范化外部查询......它使用简单的规范化。创建划分会话的递归 CTE,提取当天的标准化部分并计算尾部(将在下一次迭代中保存或划分)。并决定必须使用什么作为尾部的开始 - 也许是 05:00?
  • 如果登录发生在前一个日志日 (2021-01-03 04:44:00) 然后在第二天在线 (2021-01-03 05:02:00)- 注销在 2021-01-03 07:00:00,然后我想计算“在线”,即使之前没有“登录”,所以我想要的输出应该是:2021-01-03 05:02:00 到 2021- 01-03 07:00:00
  • 听起来很简单,我已经尝试并完成了划分每个会话,但仍然发现很难获得正确的查询来提取规范化的当天和尾部..你能通过在查询中写下来解释吗?
  • @DianAriefRisdianto 请查看this,添加所需的输出作为注释并提供一些解释并提供新链接。
猜你喜欢
  • 2021-12-30
  • 1970-01-01
  • 2014-11-28
  • 1970-01-01
  • 2012-07-25
  • 2019-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多