如何拆分数据库聚合分类ID并用于SELECT查询实现博客多分类筛选
解决多分类存储后的博客筛选问题
你现在的问题根源在于,你把多个分类ID用implode拼接成字符串存在category_id字段里(比如"1,3,5"),而原查询用=进行匹配,只会返回那些category_id完全等于目标ID的博客,自然找不到包含目标分类的内容。这里给你两种解决方案:
方案一:使用MySQL的FIND_IN_SET函数(适配现有存储结构)
MySQL的FIND_IN_SET(str, strlist)函数可以检查某个字符串是否存在于逗号分隔的字符串列表中,正好适配你的场景。同时要修复SQL注入风险,原代码直接把变量拼进SQL是非常危险的,建议改用预处理语句:
修改后的getPublishedBlogInfoByCategory函数:
public function getPublishedBlogInfoByCategory($id){ $conn = Database::dbConnection(); // 使用预处理语句避免SQL注入 $sql = "SELECT * FROM blogs WHERE FIND_IN_SET(?, category_id) ORDER BY id DESC"; $stmt = mysqli_prepare($conn, $sql); mysqli_stmt_bind_param($stmt, "s", $id); // "s"表示参数是字符串类型 mysqli_stmt_execute($stmt); $queryResult = mysqli_stmt_get_result($stmt); if($queryResult){ return $queryResult; }else{ die('Query problem: '.mysqli_error($conn)); } }
为什么用FIND_IN_SET?
比如你的category_id字段值是"1,2,3",当传入id=2时,FIND_IN_SET('2', '1,2,3')会返回该字符串在列表中的位置(这里是2),只要返回值大于0就会被匹配到,这样就能筛选出包含目标分类的博客。
方案二:优化数据库结构(推荐长期方案)
虽然FIND_IN_SET能解决当前问题,但把多个ID存在单个字段里违反了数据库的第三范式,会导致查询效率低、难以维护(比如要删除某个分类关联时很麻烦)。更规范的做法是建立多对多的中间表:
- 创建
blog_categories中间表,包含blog_id和category_id两个字段,设置为联合主键 - 当博客关联多个分类时,在中间表中插入多条记录(比如博客1关联分类1和2,就插入两条:(1,1)、(1,2))
- 查询时用关联查询:
public function getPublishedBlogInfoByCategory($id){ $conn = Database::dbConnection(); $sql = "SELECT b.* FROM blogs b JOIN blog_categories bc ON b.id = bc.blog_id WHERE bc.category_id = ? ORDER BY b.id DESC"; $stmt = mysqli_prepare($conn, $sql); mysqli_stmt_bind_param($stmt, "i", $id); // "i"表示参数是整数类型 mysqli_stmt_execute($stmt); $queryResult = mysqli_stmt_get_result($stmt); if($queryResult){ return $queryResult; }else{ die('Query problem: '.mysqli_error($conn)); } }
这种方案不仅查询效率更高,后续的分类管理也会更灵活。
额外提醒
不管用哪种方案,都要避免直接把用户输入的$id拼进SQL语句里,预处理语句是防止SQL注入的关键手段,一定要养成这个习惯。
内容的提问来源于stack exchange,提问作者Nayem323
相关产品推荐
相关产品推荐

