基于第一个表中的值的连接表中的最大值

Posted

技术标签:

【中文标题】基于第一个表中的值的连接表中的最大值【英文标题】:Max from joined table based on value from first table 【发布时间】:2021-09-13 13:33:18 【问题描述】:

我有 2 张桌子。

第一个保存作业详细信息,第二个保存这些作业运行的历史记录。第一个还包含每个客户的作业期,这是为同一客户运行下一个作业之前等待的最短时间。时间比较需要在第二张表的started_on字段上进行。

我需要找出接下来要运行的作业 ID。

架构

    job_details 表
CREATE TABLE `job_details` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `customer_id` varchar(128) NOT NULL,
  `period_in_minutes` int(11) unsigned NOT NULL,
  `status` enum('ACTIVE','INACTIVE','DELETED') DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    job_run_history 表
CREATE TABLE `job_run_history` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `job_id` int(10) unsigned NOT NULL,
  `started_on` timestamp NULL DEFAULT NULL,
  `status` enum('STREAMING','STREAMED','UPLOADING','UPLOADED','NO_RECORDS','FAILED') DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_job_id` (`job_id`),
  CONSTRAINT `fk_job_id` FOREIGN KEY (`job_id`) REFERENCES `job_details` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

job_details 表的示例数据:

INSERT INTO `job_details` (`id`, `customer_id`, `period_in_minutes`, `status`)
VALUES
    (1, 'cust1', 1, 'ACTIVE'),
    (2, 'cust2', 1, 'ACTIVE'),
    (3, 'cust3', 2, 'ACTIVE');

job_run_history 表的样本数据:

INSERT INTO `job_run_history`(`job_id`, `started_on`, `status`)
VALUES
    (1, '2021-07-01 14:38:00', 'UPLOADED'),
    (2, '2021-07-01 14:37:55', 'UPLOADED');

预期输出(在2021-07-01 14:38:56 运行时):

id
2,3
    id => 1 没有被选中,因为最后一个作业是在最后 1 分钟内开始的
    id => 2 DID 被选中,因为上一个作业开始于上一分钟之前
    id => 3 DID 被选中,因为它没有运行历史记录

我已经尝试过了,但是这与 start_time 的最大值相比无法比较,因此不起作用:

select jd.id, max(jrh.started_on) from job_details jd 
left join job_run_history jrh on jrh.job_id=jd.id 
where 
    jd.status='ACTIVE' 
    and (jrh.status is null or jrh.status not in ('STREAMING','STREAMED','UPLOADING')) 
    and (jrh.`started_on` is null or jrh.`started_on` < date_sub(now(), interval jd.`period_in_minutes`*60 second))
group by jd.id;

MySql 版本:5.7.34

有什么帮助吗?提前谢谢..

【问题讨论】:

从表中删除超出此任务的列。将数据样本添加为 INSERT INTO。为此数据提供所需的输出。并指定精确的 mysql 版本。 谢谢@Akina。完成所需的更改。 【参考方案1】:

我更喜欢使用 UNION ALL(它必须比一个复杂的查询更快):

-- the subquery for the rows which have matched ones in 2nd table
SELECT t1.id
FROM job_details t1
JOIN job_run_history t2 ON t1.id = t2.job_id
WHERE t1.status = 'ACTIVE'
  AND t2.status not in ('STREAMING','STREAMED','UPLOADING')
  AND CURRENT_TIMESTAMP - INTERVAL t1.period_in_minutes MINUTE > t2.started_on
UNION ALL
-- the subquery for the rows which have no matched ones in 2nd table
SELECT id
FROM job_details t1
WHERE NOT EXISTS ( SELECT NULL
                   FROM job_run_history t2
                   WHERE t1.id = t2.job_id )
  AND status = 'ACTIVE';

https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=8dcad95bf43ce711fdf40deda627e879

【讨论】:

我添加了第三个 job_history 行 (1, date_sub(now(), interval 80 SECOND), 'UPLOADED')。这破坏了正确性。新的 dbfiddle 链接:dbfiddle.uk/…【参考方案2】:
select jd.id from job_details jd
left join job_run_history jrh on jd.id= jrh.job_id
where jd.status = 'ACTIVE'
group by jd.id
having 
    max(jrh.started_on) < current_timestamp - interval max(jd.period_in_minutes) minute
    or 
    max(jrh.id) is null

我不确定这个过滤器是关于什么的,因为你没有在你的问题中解释它所以我没有把它放在查询中:jrh.status not in ('STREAMING','STREAMED','UPLOADING')。但是,我相信您可以在我发布的查询中实现它。

【讨论】:

这似乎工作正常。让我测试更多的案例。如果没有找到,将标记为已接受。谢谢你……dbfiddle.uk/… 找不到任何无效的案例。再次感谢...标记为已接受...

以上是关于基于第一个表中的值的连接表中的最大值的主要内容,如果未能解决你的问题,请参考以下文章

MYSQL:我想用另一个表中的值更新表中的所有行,其中第一个表中的值等于第二个表

基于匹配值的雪花SQL计数和从另一个表求和

我想要一个 pandas 脚本根据第一个电子表格中的值将一个 excel 表中的值排列到另一个表中

sql - 当我得到 2 个或更多具有相同值的值时,仅更新 1 个(查询找到的第一个)值的方法?

Laravel 连接 2 个表,第一个表中的一个数据和第二个表中的多行

将表中的所有行与其他表中的第一个匹配行连接起来[重复]