MySQL SELECT FROM表一个JOIN b WHERE不存在或已过期

时间:2017-08-24 10:47:44

标签: mysql

我有两个表,在此示例中称为表a和表b。现在,如果表a中没有匹配项,或者表b中的记录已过期,我想从表b中选择所有内容。

我在考虑在表LEFT JOINb上使用b.key IS NULL。这将为我提供表a中的所有记录,并且不匹配表a

SELECT a.id, a.title
FROM a
LEFT JOIN b ON a.id = b.a_id
WHERE b.id IS NULL

但我正在努力应对过期的部分(3天过期)。我试着像这样放入JOIN部分:

SELECT a.id, a.title
FROM a
LEFT JOIN b ON a.id = b.a_id AND b.created_at <= DATE_SUB(NOW(), INTERVAL 3 DAY)
WHERE b.id IS NULL

但这给了我没有过期的项目,而不是过期的项目。

下一个问题是,表b将有多个匹配项。这意味着它可以多次旧a_id,但所有时间戳都不同。在查询过期记录时,我只对表b的最新记录感兴趣。

预期结果

Product 3

表a

CREATE TABLE `a` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(25) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

表b

CREATE TABLE `b` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `a_id` int(11) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

数据

INSERT INTO `a` (`id`, `title`)
VALUES
    (1, 'Product 1'),
    (2, 'Product 2'),
    (3, 'Product 3');
INSERT INTO `b` (`id`, `a_id`, `created_at`)
VALUES
    (1, 1, '2017-08-20 12:30:32'),
    (2, 2, '2017-08-24 12:30:39');
    (3, 1, '2017-08-24 13:19:13');

3 个答案:

答案 0 :(得分:1)

您可以使用EXISTS子句:

SELECT a.id, a.title
FROM a
WHERE 
NOT EXISTS (SELECT 1 FROM b WHERE a.id=b.a_id) OR (
(SELECT b.created_at FROM b WHERE a.id=b.a_id 
 ORDER BY b.created_at DESC LIMIT 1) <= DATE_SUB(NOW(), INTERVAL 3 DAY))

答案 1 :(得分:0)

  

b.created_at&lt; = DATE_SUB(NOW(),INTERVAL 3 DAY)

     

但这给了我没有过期的项目,而不是过期的项目。

呃,真的,这让你难过吗?

b.created_at > DATE_SUB(NOW(), INTERVAL 3 DAY)
  

我只对表b的最新记录感兴趣

然后用:

替换b
(SELECT base.* FROM b base
 WHERE NOT EXISTS (
    SELECT 1
    FROM b prev
    WHERE prev.a_id=base.a_id
    AND prev.created_at>base.created_at
 )
) c

性能不是最佳的(并且至少有3种其他方式来编写查询)但不知道架构的样子和数据分布,我不能告诉你什么是最好的解决方案。

答案 2 :(得分:-2)

使用 LEFT OUTER JOIN而不是LEFT JOIN 即使为null,这也可以在表b上给出结果