You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony 5.1中如何在Doctrine查询中使用FIND_IN_SET与子查询?

解决Symfony 5.1中Doctrine使用FIND_IN_SET结合子查询的语法错误问题

核心问题原因

Doctrine的DQL(Doctrine Query Language)并非完全兼容原生SQL语法,直接在DQL中使用FIND_IN_SET会因为函数未注册报错,同时子查询的写法也需符合DQL规范,不能直接嵌套原生SQL字符串。

解决方案步骤

1. 注册FIND_IN_SET自定义DQL函数

在config/packages/doctrine.yaml中添加自定义函数配置,让Doctrine识别FIND_IN_SET:

doctrine:
    orm:
        entity_managers:
            default:
                dql:
                    string_functions:
                        FIND_IN_SET: DoctrineExtensions\Query\Mysql\FindInSet

注:如果没有安装doctrine-extensions,先通过Composer安装:

composer require beberlei/doctrineextensions

2. 正确编写带FIND_IN_SET的查询(以筛选属性为例)

方式一:使用DQL子查询

use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Product;
use App\Entity\ProductAttribute;

// 获取EntityManager
$em = $this->getDoctrine()->getManager();

// 子查询:获取拥有目标属性的产品ID集合
$subQuery = $em->createQueryBuilder()
    ->select('pa.product')
    ->from(ProductAttribute::class, 'pa')
    ->where('pa.attribute = :attributeId')
    ->getDQL();

// 主查询:筛选出符合条件的产品
$query = $em->createQueryBuilder()
    ->select('p')
    ->from(Product::class, 'p')
    ->where(sprintf('FIND_IN_SET(p.id, (%s)) > 0', $subQuery))
    ->setParameter('attributeId', $targetAttributeId)
    ->getQuery();

$products = $query->getResult();

方式二:使用原生SQL查询(贴近原生命令行SQL)

如果DQL写法受限,直接用原生SQL更直接:

$targetAttributeId = 123; // 替换为实际筛选的属性ID
$sql = "
    SELECT p.*
    FROM product p
    WHERE FIND_IN_SET(p.id, (
        SELECT pa.product_id
        FROM product_attribute pa
        WHERE pa.attribute_id = :attributeId
    )) > 0
";

$stmt = $em->getConnection()->prepare($sql);
$stmt->execute(['attributeId' => $targetAttributeId]);
$products = $stmt->fetchAllAssociative();

3. 扩展为多属性筛选(类似亚马逊多选项筛选)

如果要支持多个属性同时筛选(比如同时选颜色和尺寸),可以调整子查询为分组统计:

$attributeIds = [123, 456]; // 多个属性ID

$subQuery = $em->createQueryBuilder()
    ->select('pa.product')
    ->from(ProductAttribute::class, 'pa')
    ->where('pa.attribute IN (:attributeIds)')
    ->groupBy('pa.product')
    ->having('COUNT(DISTINCT pa.attribute) = :attributeCount')
    ->getDQL();

$query = $em->createQueryBuilder()
    ->select('p')
    ->from(Product::class, 'p')
    ->where(sprintf('FIND_IN_SET(p.id, (%s)) > 0', $subQuery))
    ->setParameter('attributeIds', $attributeIds)
    ->setParameter('attributeCount', count($attributeIds))
    ->getQuery();

$products = $query->getResult();

关键注意事项

  • 确保所有实体映射关系正确,特别是Product与ProductAttribute的一对多关联配置无误。
  • FIND_IN_SET是MySQL特有函数,若切换数据库需调整对应函数。
  • 大数量数据下,建议为product_attribute.product_id和product_attribute.attribute_id建立联合索引,提升查询性能。

内容的提问来源于stack exchange,提问作者Mike Zhang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 08:40:31