1.举个栗子,业务应用场景

首先来点数据:
sql语句(数据库使用的是mysql)如下:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for test_newest
-- ----------------------------
DROP TABLE IF EXISTS `test_newest`;
CREATE TABLE `test_newest`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `course_id` int(11) NOT NULL,
  `start_date` datetime(0) NULL DEFAULT NULL,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of test_newest
-- ----------------------------
INSERT INTO `test_newest` VALUES (1, 1, '2020-03-03 11:57:00', '课程1 最新');
INSERT INTO `test_newest` VALUES (2, 2, '2020-03-18 11:57:15', '课程2');
INSERT INTO `test_newest` VALUES (3, 3, '2020-03-03 11:57:30', '课程3');
INSERT INTO `test_newest` VALUES (4, 4, '2020-03-03 11:57:44', '课程4');
INSERT INTO `test_newest` VALUES (5, 1, '2020-01-27 11:57:56', '课程1');
INSERT INTO `test_newest` VALUES (6, 1, '2020-02-11 11:58:15', '课程1');
INSERT INTO `test_newest` VALUES (7, 3, '2020-04-26 11:58:36', '课程3最新');
INSERT INTO `test_newest` VALUES (8, 4, '2020-03-27 11:59:03', '课程4最新');
INSERT INTO `test_newest` VALUES (9, 5, '2020-03-04 12:01:03', '课程5');

SET FOREIGN_KEY_CHECKS = 1;

建立好的表:

mysql获取重复数据中时间最接近给定值的数据 sql重复数据取日期小的_数据库


说明:该表包含 id主键, 课程id,开始日期,和课程名。

现在的需求是:找出最新的课程的全部信息。补充:即,找出课程id相同,且开始日期是最近的一条记录。

2.思考:

首先想到的是使用group by 然后order by start_date desc倒序排序,再接着使用imit 限制记录1 条 ,想过使用连表查询,但真正去尝试,结果发现个人解决不了这个问题或许是功底不够吧->_->。
之前想到一个,不过查出来的却不满足条件:

select id,course_id, max(start_date),name from test_newest where course_id in(select distinct(course_id) from test_newest
	
	)   group by course_id

结果:

mysql获取重复数据中时间最接近给定值的数据 sql重复数据取日期小的_java_02

可是课程名不对啊,"课程3"名称应该是“课程3最新“而且id也不对,只是把日期换了,其他的数据不对,哎,如果再多一些其他字段值又不一样,那数据肯定乱套了。

3.由内到外的解决方案

使用嵌套查询,从内层逐步向外,解决问题。中心思想:将内层查出来的结果作为外层的条件。
先查看表:判断出需要的数据结果应该是 id为:1,2,7,8,9所对应的记录
*

mysql获取重复数据中时间最接近给定值的数据 sql重复数据取日期小的_sql_03

执行总sql语句,即可查询满足条件的内容:

SELECT
	* 
FROM
	test_newest 
WHERE
	id IN (
	SELECT
		m.Ids 
	FROM
		(
		SELECT DISTINCT
			( course_id ) AS courseId,
			( SELECT id FROM test_newest WHERE course_id = courseId ORDER BY start_date DESC LIMIT 0, 1 ) AS Ids 
		FROM
			test_newest 
		WHERE
			course_id IN ( SELECT DISTINCT ( course_id ) FROM test_newest ) 
		) AS m 
	)

sql说明:这个语句比较复杂(以下由内到外进行讲解),先看第一步
1)执行下面的sql: SELECT DISTINCT ( course_id ) FROM test_newest 查出所有不重复的course_id,作为第一个条件 条件1

mysql获取重复数据中时间最接近给定值的数据 sql重复数据取日期小的_mybatis_04


2)将条件1带入下面的sql ,注意下面这种写法,将courseId作为 该条select语句中另一个字段的条件select id from test_newtest where course_id=courseId … , distinct仍然需要加上**(特殊说明:在真实的业务场景中可能条件需要从前端传入过来,此时可以直接在字段sql中使用#{传递值}获取),这样可以保证查询出来的Ids是不会重复的。
将下面sql查询的结果作为 条件2

SELECT DISTINCT ( course_id ) AS courseId,
			( SELECT id FROM test_newest WHERE course_id = **courseId** ORDER BY start_date DESC LIMIT 0, 1 ) AS Ids 
		FROM
			test_newest 
		WHERE
			course_id IN (条件1 )

mysql获取重复数据中时间最接近给定值的数据 sql重复数据取日期小的_mysql_05


3) 由于条件2不是一个字段,所以可以看成一张新的中间表,从中间表中查出某个字段,这个容易理解,将下面sql执行的结果作为 条件3

SELECT
		m.Ids 
	FROM
		(
		 条件2
		) AS m

mysql获取重复数据中时间最接近给定值的数据 sql重复数据取日期小的_数据库_06


4)这个更容易理解,查询某个条件下的记录。

SELECT
	* 
FROM
	test_newest 
WHERE
	id IN  ( 条件3)

mysql获取重复数据中时间最接近给定值的数据 sql重复数据取日期小的_sql_07

总sql:

SELECT
	* 
FROM
	test_newest 
WHERE
	id IN (
	SELECT
		m.Ids 
	FROM
		(
		SELECT DISTINCT
			( course_id ) AS courseId,
			( SELECT id FROM test_newest WHERE course_id = courseId ORDER BY start_date DESC LIMIT 0, 1 ) AS Ids 
		FROM
			test_newest 
		WHERE
			course_id IN ( SELECT DISTINCT ( course_id ) FROM test_newest ) 
		) AS m 
	)

特殊讲解:
select
字段1
(select 字段 from
表1 as a
where a.字段=字段1 ) as 字段2
from
表2
这个写法比较经典。表一和表二可以是同一张表也可以不同。其实字段2可以有由多张表各种连接查出来。只要保证与字段以是1对1 或1对空就行。
原理猜测:
每获取一条记录时:
执行顺序:
1> 先进行select 字段1 from 表2 获得字段1
2>接着执行select 字段 from 表1 where 表1的字段 = 字段1
将获得的唯一的一个字段值作为字段2
3>最后执行 select 字段1,字段2 将查询的结果作为一条记录。

最后重复上述步骤。

个人说明:如有疏漏之处或有更好的方案,还请各位指教。