Doctrine2 DBAL存在查询

时间:2016-12-14 10:52:27

标签: mysql symfony dbal

我想通过使用Doctrine2 DBAL构建的QueryBuilder查询来请求您的帮助。我已经习惯了ORM,但我认为对于这样的查询来说这是一种过度杀戮,而这种查询是在听众中调用的。

我需要SELECT EXISTS的查询,而且我不知道如何使用DBAL QueryBuilder构建它。

我已经创建了一个子查询:

$subQuery = $connection->createQueryBuilder();
$subQuery
    ->select('o.id')
    ->from('order', 'o')
    ->leftJoin('o', 'payment', 'p')
    ->where($subQuery->expr()->isNull('p.id'))
;

我基本上想检查是否有任何未付的订单。我现在不知道如何构建SELECT EXISTS查询?谁能指出我正确的方向?我在考虑这样的事情:

$qb->select('EXISTS(?)')->setParameter($subQuery->getDQL())

这是正确的解决方案吗?

@EDIT

经过一段时间的思考,我决定改用ORM。不幸的是,这也不起作用,我收到了错误:

line 0, col 7: Error: Expected known function, got 'EXISTS'

DQL是: SELECT EXISTS(<subquery here>)

考虑到它是用QueryBuilder构建的,这有点奇怪:

/* @var $qb QueryBuilder */
$qb = $this->em->createQueryBuilder();
$qb
        ->select($qb->expr()->exists($subQuery->getDQL()));

1 个答案:

答案 0 :(得分:2)

晚了几年,但是您需要在QueryBuilder的EXISTSSELECT语句部分内指定WHERE子查询SQL,而不是使用参数。

另外,由于order是MySQL中的保留字,因此您将需要使用标识符引号`(反引号)来转义表名。

使用ORM时;您必须指定引用实体的FROM语句,因此您需要更改方法。

$connection = $this->em->getConnection();
$expr = $connection->getExpressionBuilder();
$qbSub = $connection->createQueryBuilder()
    ->select(['1'])
    ->from('`order`', 'o')
    ->leftJoin('o', '`payment`', 'p', $exor->eq('p.order_id', 'o.id'))
    ->where($expr->isNull('p.id'));

/**
 * @return string "1" if a record exists, "0" otherwise
 */
$connection->createQueryBuilder()
    ->select('EXISTS(' . $qbSub->getSQL() . ')')
    ->execute()
    ->fetchColumn();

注意:如果有任何参数,则必须在顶层使用QueryBuilder::setParameter()绑定占位符的值 查询,而不是子查询。

$qb
    ->setParameter('name', $value)
    ->execute();

生成的SQL

SELECT EXISTS(
   SELECT 1
   FROM `order` AS o
   LEFT JOIN `payment` AS p
   ON p.order_id = o.id
   WHERE p.id IS NULL
);

但是,我建议将您的查询从排除联接更改为NOT EXISTS的包括联接。这样做会从结果集中过滤出已付款的订单。而不是尝试加入每个付款的每个订单并检索返回null的付款。显着提高查询性能。

示例db-fiddle

SELECT EXISTS (
    SELECT 1
    FROM `order` AS o2
    WHERE NOT EXISTS(
        SELECT NULL
        FROM `order` AS o
        INNER JOIN `payment` AS p
        ON p.order_id = o.id
        WHERE o2.id = o.id
    )
)