能否将两段SQL查询逻辑合并为单一SQL语句?
简化RedBeanPHP逻辑为单一SQL查询
需求说明
按id升序获取第一条记录:
- 若该记录的
media_group为NULL,仅返回这条记录 - 若
media_group不为NULL,返回所有media_group值与该条记录相同的记录
原代码问题
原实现分两次查询,效率偏低且存在SQL注入风险(直接拼接media_group值)。以下是简化后的单一SQL方案,同时修复注入问题。
方案1:基础子查询写法
通过子查询获取第一条记录的media_group,再根据其值筛选结果:
SELECT * FROM `prn` WHERE -- 第一条记录media_group为NULL时,仅匹配该记录的id (SELECT media_group FROM `prn` ORDER BY id ASC LIMIT 1) IS NULL AND id = (SELECT id FROM `prn` ORDER BY id ASC LIMIT 1) -- 否则匹配所有同media_group的记录 OR media_group = (SELECT media_group FROM `prn` ORDER BY id ASC LIMIT 1)
对应RedBeanPHP代码:
$records = R::getAll(' SELECT * FROM `prn` WHERE (SELECT media_group FROM `prn` ORDER BY id ASC LIMIT 1) IS NULL AND id = (SELECT id FROM `prn` ORDER BY id ASC LIMIT 1) OR media_group = (SELECT media_group FROM `prn` ORDER BY id ASC LIMIT 1) ');
方案2:CTE优化写法(更高效)
使用CTE(公共表表达式)仅查询一次第一条记录,避免重复子查询,提升性能:
WITH first_record AS ( SELECT id, media_group FROM `prn` ORDER BY id ASC LIMIT 1 ) SELECT p.* FROM `prn` p JOIN first_record fr ON -- media_group为NULL时匹配id (fr.media_group IS NULL AND p.id = fr.id) -- 否则匹配media_group OR (p.media_group = fr.media_group)
对应RedBeanPHP代码:
$records = R::getAll(' WITH first_record AS ( SELECT id, media_group FROM `prn` ORDER BY id ASC LIMIT 1 ) SELECT p.* FROM `prn` p JOIN first_record fr ON (fr.media_group IS NULL AND p.id = fr.id) OR (p.media_group = fr.media_group) ');
说明
两种方案均完全覆盖原逻辑,且无需手动拼接参数,避免了SQL注入风险。CTE写法在数据量较大时性能更优,因为仅执行一次获取第一条记录的查询。
内容的提问来源于stack exchange,提问作者Nzr
相关产品推荐
相关产品推荐

