首页 > 解决方案 > 如何使用queryBuilder修复“错误:预期文字,得到'SELECT'”?

问题描述

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

"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”。所以我做了一个子查询,因为我想要其他条件(总是更新最后一个)。我做了一个子查询,因为我无法在更新查询中添加选择。

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

“从 App\Entity\Event e 中选择 MAX(e.arrivedAt) 其中 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)"

新 =

“更新 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"

子查询

“从 App\Entity\Event ev WHERE ev.camera=:var3 中选择 MAX(ev.arrivedAt)”

标签: sqlsymfonydoctrine-ormdoctrinequery-builder

解决方案


我会尝试做这样的事情:

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()在这里阅读更多
  • 避免将 DQL 与伪原生(LIKEIN等)SQL 混合使用。如果 Doctrine 读取了一些它不能使用的原生 SQL,它会咀嚼你。改为使用expr()。如果您在 中找不到您需要的内容expr(),则意味着您应该创建一个原生查询。
  • 完整命名您的别名,以便以后阅读。

[编辑]

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

除了别名之外,我们可以看到子查询周围缺少一对括号。刚刚在我的答案中添加了它们。如果您复制/粘贴我的代码,它应该可以解决您的问题。


推荐阅读