How to fix "Error: Expected Literal, got 'SELECT'" with queryBuilder?

How to fix "Error: Expected Literal, got 'SELECT'" with queryBuilder?

我的查询有问题,当我尝试进行子查询时出现此错误消息

"hydra:description": "[Syntax Error] line 0, col 85: Error: Expected Literal, got 'SELECT'",

对于我的 EventRepositoty 中的这个查询 CLass:

public function updateMoveAtField(string $eventLabel, $cameraId)
{
    $queryBuilder = $this->createQueryBuilder('e');
    $subQueryBuilder = $this->createQueryBuilder('ev');

    $subQuery = $subQueryBuilder
        ->select('MAX(ev.arrivedAt) as arrived')
        ->andWhere('ev.camera = ?1')
        ->setParameter(1, $cameraId)
        ->getQuery()->getDQL()
    ;

    $event = $queryBuilder
        ->update()
        ->set('e.moveAt', '?1')
        ->where('e.label = ?2')
        ->andWhere('e.camera = ?3')
        ->andWhere($queryBuilder->expr()->andX($subQuery))
        ->setParameter(1, new \DateTime())
        ->setParameter(2, $eventLabel)
        ->setParameter(3, $cameraId);

    return $event->getQuery()->execute();
}

我该如何解决?

我不知道你是否能理解我的要求所以让我解释一下:我想更新一个字段 "moveAt" 当标签和相机与查询中发送的相同时。所以我做了一个子查询,因为我想要和其他条件(总是更新最后一个)。我做了一个子查询,因为我不能在更新查询中添加 select。

编辑: 来自@Preciel 帮助的 DQL 转储结果

"SELECT MAX(e.arrivedAt) FROM App\Entity\Event e WHERE e.label=:var2 AND e.camera=:var3 AND e.camera=:var3 AND (e.arrivedAt <= SELECT MAX(e.arrivedAt) FROM App\Entity\Event e WHERE e.label=:var2 AND e.camera=:var3 AND e.camera=:var3)"

新=

"UPDATE App\Entity\Event e SET event.moveAt = :var1 WHERE e.label=:var2 AND e.camera=:var3 AND e.arrivedAt <= SELECT MAX(ev.arrivedAt) FROM App\Entity\Event ev WHERE ev.camera=:var3"

子查询

"SELECT MAX(ev.arrivedAt) FROM App\Entity\Event ev WHERE ev.camera=:var3"

我会尝试做这样的事情:

public function updateMoveAtField($eventLabel, $cameraId) {
    $qb=$this->createQueryBuilder("event");
    $sqb=$this->createQueryBuilder("eventBis");

    $qb->update()
       ->set("event.moveAt", ":var1")
       ->andWhere("event.lavel=:var2")
       ->andWhere("event.camera=:var3")
       ->andWhere(
           $qb->expr()->lte("event.arrivedAt",
               "(".$sqb->select($qb->expr()->max("eventBis.arrivedAt"))  //Your sub query start here
                   ->andWhere("eventBis.camera=:var3")->getDQL().")")) //and end here
       ->setParameters(array(
           'var1'=>new \DateTime(),
           'var2'=>$eventLabel,
           'var3'=>$cameraId,
       ));

    // dump($qb->getDQL());
    // dump($qb->getQuery()->getSQL());
    // exit();

    return $qb->getQuery()->execute();
}

我添加了 2 行转储。如果不行,请先转储DQL,然后SQL(SQL可能会失败),请在评论中添加。

在第一次使用expr()时,我使用了lte()(小于等于)。 根据您的需要更改它(gt()、gte()、eq()、lte()、lt())。

提示:

  • 始终在查询中使用双引号。 Doctrine 将只接受字符串值的单引号(单引号可以用于参数)。
  • 从不使用 where(),始终以 andWhere()orWhere()
  • 开头
  • 避免同时使用 andWhere()orWhere()。更喜欢 expr() (read more here)
  • 避免将 DQL 与伪原生(LIKEIN 等)混合使用 SQL。如果 Doctrine 阅读一些它不能使用的本地 SQL ,它会咀嚼你。请改用 expr()。如果您在 expr() 中找不到您需要的内容,则意味着您应该创建一个本机查询。
  • 完整命名您的别名,以便以后阅读。

[编辑]

这是我的回答中给出的转储查询的屏幕截图。 我认为您试图使我的查询适应您的代码,而不仅仅是 copy/paste 它。别名与我在查询中写的不匹配。

除了别名,我们还可以看到子查询周围少了一对括号。刚刚在我的回答中添加了它们。如果您 copy/paste 我的代码,它应该可以解决您的问题。