商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > 如何按主题分组并有序显示数据库内容(Udemy式课程目录效果)

如何按主题分组并有序显示数据库内容(Udemy式课程目录效果)

  发布于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 值发生变化时才输出标题——这完美规避了重复标题问题,而且完全依赖数据的物理顺序,无需额外数组或嵌套循环。

完整可运行示例(含HTML结构优化)

// 数据查询(已预处理)$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:原问题中$email直接拼入查询存在严重注入风险,必须改用prepare() + execute();
  • 空数据兜底:在foreach前检查count($rows) > 0,避免无结果时页面空白;
  • CSS可扩展性:为.topic-section和.curriculum-item添加样式,可以轻松实现折叠/展开、图标、计数等Udemy风功能;
  • 性能考虑:如果数据量极大(超过10k行),建议在(email, topic)上建立联合索引,加速GROUP BY和JOIN。

通过“排序逻辑前置到SQL + 渲染逻辑轻量化”的组合策略,你既能精准控制展示顺序,又能保持PHP层代码清晰高效。说白了,这才是生产环境推荐的课程目录实现方式。

本文转载于:https://www.php.cn/faq/2345568.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注