Doctrine中带有LIMIT的子查询

4

我正在尝试使用Doctrine进行具有子查询的查询。目前它给了我一个错误。我的存储库中的函数是:

public function getRecentPlaylists($count = 3) {


    $q = $this->_em->createQuery("
            SELECT p.id,
            p.featuredImage,
            p.title,
            p.slug,         
            a.firstName,
            a.lastName,
            a.slug as authorSlug,
            (SELECT updated 
                     FROM \Entities\Articles 
                     ORDER BY updated DESC LIMIT 1) as updated
            FROM \Entities\Playlist p
            JOIN \Entities\Account a
                        ON p.account_id = a.id
            ")
        ->setMaxResults($count);

            try{    
            return $q->getResult();
            }catch(Exception $e){
                echo $e->message();
            }

}
这给我带来了这个错误:
[Semantical Error] line 0, col 210 near 'LIMIT 1) as updated FROM': Error: Class 'LIMIT' is not defined.

我几乎放弃了Doctrine,我一直无法弄清楚如何使用子查询或带有子查询的联合查询。有关此功能的任何帮助?谢谢!


我没有使用Doctrine的经验,但你尝试过将as改为大写的AS吗? - Brobin
3个回答

21

正如Colin O'Dell在他的博客中所解释的那样,您可以很容易地将自己的语法添加到Doctrine中,例如在子查询中添加LIMIT 1

// AppBundle\DBAL\FirstFunction
<?php

use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\Subselect;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;

/**
 * FirstFunction ::=
 *     "FIRST" "(" Subselect ")"
 */
class FirstFunction extends FunctionNode
{
    /**
     * @var Subselect
     */
    private $subselect;

    /**
     * {@inheritdoc}
     */
    public function parse(Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->subselect = $parser->Subselect();
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }

    /**
     * {@inheritdoc}
     */
    public function getSql(SqlWalker $sqlWalker)
    {
        return '(' . $this->subselect->dispatch($sqlWalker) . ' LIMIT 1)';
    }
}
# app/config/config.yml
doctrine:
    # ...
    orm:
        # ...
        dql:
            string_functions:
                FIRST: AppBundle\DBAL\FirstFunction

使用方法如下:

$dqb->from('MyAppBundle:Foo', 'foo')
    ->leftJoin('foo.bar', 'bar', 'WITH', 'bar = FIRST(SELECT b FROM MyAppBundle:Bar b WHERE b.foo = foo AND b.published_date >= :now ORDER BY t.startDate)');

1
但是如果我需要例如 LIMIT 15 怎么办?这将有所帮助,Doctrine 返回错误,子查询返回了多个结果(而不是一个)。 - Vladimir Ch
你是我的英雄@simon-epskamp!非常感谢。我对函数SUB_LIMIT(<limit>,<subquery>)进行了更改。 - Joachim

10

在这种情况下,您可以使用Doctrine的聚合表达式MAX来获取最近的日期:

SELECT MAX(a.updated) FROM AppBundle:Article a

您无需使用LIMIT。


-9
你需要做的是将内部查询提取出来,单独为其创建DQL,然后在内部使用生成的DQL。
$inner_q = $this->_em
    ->createQuery("SELECT AR.updated FROM \Entities\Articles AR ORDER BY AR.updated DESC")
    ->setMaxResults(1)
    ->getDQL();

$q = $this->_em->createQuery("SELECT p.id,
        p.featuredImage,
        p.title,
        p.slug,         
        a.firstName,
        a.lastName,
        a.slug as authorSlug,
        (".$inner_q.") AS updated
        FROM \Entities\Playlist p
        JOIN \Entities\Account a
             ON p.account_id = a.id
    ")
    ->setMaxResults($count);
try{    
    return $q->getResult();
}
catch(Exception $e){
    echo $e->message();
}

谢谢你的回答。这给了我一个错误:第0行,第289列附近出现了“a”:错误:在连接路径表达式中使用的实体变量\ Entities \ Account未在之前定义。 - raygo
@raygo 你可以使用 var_dump($q->getSQL()); 来输出查询语句,然后将该查询语句粘贴到你的 MySQL 数据库中,查看错误所在;通过修改 SQL 查询语句来解决问题,然后将这些更改应用到你的 DQL 中。 - Javad
这个解决方案还有效吗?在我的情况下,当转换为SQL时,子查询没有“LIMIT”子句... - Oscar Pérez
17
这不起作用。setMaxResults在子查询中被忽略。 - cesar moro
它适用于我的查询。 - pedram shabani
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,