发布于2026-07-18 阅读(0)
扫一扫,手机访问
本文介绍如何从数据库中查询带主题(topic)和内容(sentence)的记录,并按主题首次出现顺序分组展示,每个主题仅标题显示一次,其下罗列所有对应句子,实现类似udemy课程大纲的清晰结构。
今天来聊聊一个挺常见的需求:怎么把数据库里带主题和句子的记录,按主题分组展示,而且每个主题标题只出现一次,下面罗列所有对应的句子。效果就像Udemy的课程大纲一样,清晰又有层次。核心思路其实就两步:数据预排序和前端逻辑去重渲染。
很多人习惯直接ORDER BY topic,但这样会按字母顺序排列,比如Amazon、Google、YouTube,跟实际需求不符。我们需要的是按主题首次出现的顺序,比如Google先出现(ID=1),那它就应该排第一,YouTube(ID=2)第二,Amazon(ID=3)第三。这时候,就得用子查询来搞定:先找出每个主题的最小ID,然后以此为基准排序。
SELECT c.*FROM ( SELECT MIN(id) AS min_id, topic FROM contents WHERE email = ? GROUP BY topic) tJOIN contents c ON c.topic = t.topicORDER BY t.min_id, c.id;
✅ 优势:
- 使用 MIN(id) 确保主题分组顺序严格遵循原始数据中该主题的首次出现位置;
- JOIN 保证不丢失任何句子;
- 最终结果按 min_id(主题序)+ c.id(句内序)双重排序,天然满足展示逻辑。
说到安全,这个必须单独拎出来说。务必要用预处理语句防止SQL注入,像下面这样:
$stmt = $db_conn->prepare(" SELECT c.* FROM ( SELECT MIN(id) AS min_id, topic FROM contents WHERE email = ? GROUP BY topic ) t JOIN contents c ON c.topic = t.topic ORDER BY t.min_id, c.id");$stmt->execute([$email]);$select = $stmt->fetchAll(PDO::FETCH_ASSOC);数据排好序后,PHP渲染逻辑就变得特别简洁了:
$last_topic = '';foreach ($select as $row) { $topic = $row['topic']; $sentence = $row['sentence']; // 仅当主题变更时输出 标题 if ($topic !== $last_topic) { echo "{$topic}
"; $last_topic = $topic; } echo "
{$sentence}
";}? 原理说明:
利用 $last_topic 缓存上一次处理的主题名,仅在 topic 值发生变化时才输出标题——这完美规避了重复标题问题,而且完全依赖数据的物理顺序,无需额外数组或嵌套循环。
// 数据查询(已预处理)$stmt = $db_conn->prepare("..."); // 同上$stmt->execute([$email]);$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);// 渲染$last_topic = '';echo '';foreach ($rows as $row) { if ($row['topic'] !== $last_topic) { // 关闭前一个主题的容器(如有需要) if ($last_topic !== '') echo ''; echo ''; echo "{$row['topic']}
"; $last_topic = $row['topic']; } echo "{$row['sentence']}";}// 关闭最后一个 sectionif ($last_topic !== '') echo ' ';echo '';通过“排序逻辑前置到SQL + 渲染逻辑轻量化”的组合策略,你既能精准控制展示顺序,又能保持PHP层代码清晰高效。说白了,这才是生产环境推荐的课程目录实现方式。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8