首先来点数据:
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;
建立好的表:
说明:该表包含 id主键, 课程id,开始日期,和课程名。
现在的需求是:找出最新的课程的全部信息。补充:即,找出课程id相同,且开始日期是最近的一条记录。
首先想到的是使用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
结果:可是课程名不对啊,"课程3"名称应该是“课程3最新“而且id也不对,只是把日期换了,其他的数据不对,哎,如果再多一些其他字段值又不一样,那数据肯定乱套了。
使用嵌套查询,从内层逐步向外,解决问题。中心思想:将内层查出来的结果作为外层的条件。
先查看表:判断出需要的数据结果应该是 id为:1,2,7,8,9所对应的记录
*
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。
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 )
3) 由于条件2不是一个字段,所以可以看成一张新的中间表,从中间表中查出某个字段,这个容易理解,将下面sql执行的结果作为 条件3
SELECT
m.Ids
FROM
(
条件2
) AS m
SELECT
*
FROM
test_newest
WHERE
id IN ( 条件3)
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 将查询的结果作为一条记录。
最后重复上述步骤。
个人说明:如有疏漏之处或有更好的方案,还请各位指教。