如何随机选择学说

Yas*_*984 32 php dql doctrine-orm

以下是我在数据库中查询某些单词的方法

$query = $qb->select('w')
    ->from('DbEntities\Entity\Word', 'w')
    ->where('w.indictionary = 0 AND w.frequency > 3')
    ->orderBy('w.frequency', 'DESC')
    ->getQuery()
    ->setMaxResults(100);
Run Code Online (Sandbox Code Playgroud)

我正在使用mysql,我想获得符合条件的随机行,我会在查询中使用rand()命令.

我发现这个类似的问题基本上表明,因为在学说中不支持ORDER BY RAND,你可以随机化主键.但是,这不能在我的情况下完成,因为我有一个搜索条件和一个where子句,以便不是每个主键都满足该条件.

我还发现了一个代码片段,建议你使用OFFSET随机化行,如下所示:

$userCount = Doctrine::getTable('User')
     ->createQuery()
     ->select('count(*)')
     ->fetchOne(array(), Doctrine::HYDRATE_NONE); 
$user = Doctrine::getTable('User')
     ->createQuery()
     ->limit(1)
     ->offset(rand(0, $userCount[0] - 1))
     ->fetchOne();
Run Code Online (Sandbox Code Playgroud)

我有点困惑的是,这是否会帮助我解决在我的情况下随机缺乏对订单的支持.我无法在setMaxResult之后添加偏移量.

知道如何实现这一目标吗?

Ben*_*min 42

Doctrine团队不愿意实现此功能.

您的问题有几种解决方案,每种解决方案都有其自身的缺点:

  • 添加自定义数字函数:请参阅此DQL RAND()函数
    (如果您有许多匹配的行,可能会很慢)
  • 使用本机查询
    (我个人试图避免这种解决方案,我发现很难维护)
  • 首先发出原始SQL查询以随机获取一些ID,然后使用DQL WHERE x.id IN(?)加载关联的对象,方法是将ID数组作为参数传递.
    此解决方案涉及两个单独的查询,但可能提供比第一个解决方案更好的性能(除了ORDER BY RAND()存在之外的其他原始SQL技术,我不会在这里详细说明,您将在此网站上找到一些好的资源).

  • 好的,根据[这个链接](https://groups.google.com/forum/?fromgroups#!topic/doctrine-user/P5o1Cc0apec),你只能通过`SELECT`来`ORDER BY`自定义函数第一的。这应该是类似“SELECT w, RAND() AS r FROM Word w ORDER BY r”的内容。 (2认同)

HMa*_*gdy 31

跟着这些步骤:

在项目中定义一个新类:

namespace My\Custom\Doctrine2\Function;

use Doctrine\ORM\Query\Lexer;

class Rand extends \Doctrine\ORM\Query\AST\Functions\FunctionNode
{

    public function parse(\Doctrine\ORM\Query\Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }

    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
    {
        return 'RAND()';
    }
}
Run Code Online (Sandbox Code Playgroud)

注册课程 config.yml:

doctrine:
     orm:
         dql:
             numeric_functions:
                 Rand: My\Custom\Doctrine2\Function\Rand
Run Code Online (Sandbox Code Playgroud)

直接使用它:

$qb->addSelect('RAND() as HIDDEN rand')->orderBy('rand');
Run Code Online (Sandbox Code Playgroud)

  • 在我看来,这显然是最好的解决方案,因为您仍然可以使用 DQL/querybuilder 和 Doctrine,而且还具有 SQL 性能。对我来说,orderBy 子句需要是“rand”而不是“rand()”才能工作(这是有道理的,因为您使用的是 var 而不是调用函数)。 (2认同)

Jon*_*nny 19

根据Hassan Magdy Saad的建议,您可以使用流行的DoctrineExtensions库:

请参阅此处的mysql实现:https://github.com/beberlei/DoctrineExtensions/blob/master/src/Query/Mysql/Rand.php

# config.yml

doctrine:
     orm:
         dql:
             numeric_functions:
                 rand: DoctrineExtensions\Query\Mysql\Rand
Run Code Online (Sandbox Code Playgroud)

在Doctrine ORM 2.6.x-dev中测试,您可以实际执行:

->orderBy('RAND()')
Run Code Online (Sandbox Code Playgroud)


小智 9

或者你可以这样做 - >

$words = $em->getRepository('Entity\Word')->findAll();
shuffle($words);
Run Code Online (Sandbox Code Playgroud)

当然,如果您有许多记录,这将是非常低效的,因此请谨慎使用.

  • “非常低效”是一个非常重要的细节。 (2认同)

Krz*_*zos 6

为什么不使用存储库?

<?php

namespace Project\ProductsBundle\Entity;

use Doctrine\ORM;

class ProductRepository extends ORM\EntityRepository
{
    /**
     * @param int $amount
     * @return Product[]
     */
    public function getRandomProducts($amount = 7)
    {
        return $this->getRandomProductsNativeQuery($amount)->getResult();
    }

    /**
     * @param int $amount
     * @return ORM\NativeQuery
     */
    public function getRandomProductsNativeQuery($amount = 7)
    {
        # set entity name
        $table = $this->getClassMetadata()
            ->getTableName();

        # create rsm object
        $rsm = new ORM\Query\ResultSetMapping();
        $rsm->addEntityResult($this->getEntityName(), 'p');
        $rsm->addFieldResult('p', 'id', 'id');

        # make query
        return $this->getEntityManager()->createNativeQuery("
            SELECT p.id FROM {$table} p ORDER BY RAND() LIMIT 0, {$amount}
        ", $rsm);
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

Doctrine 2不支持ORDER BY rand(),但是我发现这篇文章包含对此的修复是个问题.

  • 当我们有JOIN SQL时,那篇文章就是了 (2认同)