如何教义随机选择如何教义随机选择(How to select randomly with doctr

2019-05-14 14:41发布

这是我如何查询我的数据库的一些话

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

我使用的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();

我有点困惑,这是否会帮助我在我的情况还是不解决缺乏支持顺序随机。 我是不是能够setMaxResult后增加所抵消。

任何想法,这可怎么实现的?

Answer 1:

该学说的团队是不是愿意来实现此功能 。

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

  • 添加自定义数字功能 :看到这个DQL RAND()函数
    (如果你有很多的匹配行可能会慢)
  • 使用原生查询
    (我个人尽量避免这种解决方案,我发现很难维持)
  • 首先发出原始SQL查询来获得一些随机的ID,然后使用DQL WHERE x.id IN(?)来加载相关联的对象,通过传递ID的数组作为参数。
    该解决方案包括两个单独的查询,但可能给比第一个解决方案更好的性能(其他原材料SQL技术比ORDER BY RAND()存在,在这里我就不详细介绍它们,你会发现这个网站上的一些很好的资源)。


Answer 2:

跟着这些步骤:

在您的项目定义一个新类:

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()';
    }
}

注册类config.yml

doctrine:
     orm:
         dql:
             numeric_functions:
                 Rand: My\Custom\Doctrine2\Function\Rand

直接使用它:

$qb->addSelect('RAND() as HIDDEN rand')->orderBy('rand');


Answer 3:

在什么哈桑Magdy萨阿德行建议 ,你可以使用流行的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

在学说ORM的2.6.x-dev的测试,可以再真正做到:

->orderBy('RAND()')


Answer 4:

或者你可以做到这一点 - >

$words = $em->getRepository('Entity\Word')->findAll();
shuffle($words);

当然,如果你有很多记录谨慎所以使用这将是非常低效的。



Answer 5:

原则2不支持ORDER BY RAND(),但我发现这个文章,其中包含的修补程序,这是问题。



Answer 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);
    }
}


Answer 7:

混洗可以在查询(阵列)结果来完成,但是改组不随机挑选。

为了从实体随机挑选我喜欢做这在PHP中,这可能会减缓随机挑选,但它可以让我继续测试我在做什么,使最终的调试更容易控制。

下面的例子将所有的ID从所述实体到一个数组,我可以然后在PHP使用“随机治疗”。

public function getRandomArt($nbSlotsOnPage)
{
    $qbList=$this->createQueryBuilder('a');

    // get all the relevant id's from the entity
    $qbList ->select('a.id')
            ->where('a.publicate=true')
            ;       
    // $list is not a simple list of values, but an nested associative array
    $list=$qbList->getQuery()->getScalarResult();       

    // get rid of the nested array from ScalarResult
    $rawlist=array();
    foreach ($list as $keyword=>$value)
        {
            // entity id's have to figure as keyword as array_rand() will pick only keywords - not values
            $id=$value['id'];
            $rawlist[$id]=null;
        }

    $total=min($nbSlotsOnPage,count($rawlist));
    // pick only a few (i.e.$total)
    $keylist=array_rand($rawlist,$total);

    $qb=$this->createQueryBuilder('aw');
    foreach ($keylist as $keyword=>$value)
        {
            $qb ->setParameter('keyword'.$keyword,$value)
                ->orWhere('aw.id = :keyword'.$keyword)
            ;
        }

    $result=$qb->getQuery()->getResult();

    // if mixing the results is also required (could also be done by orderby rand();
    shuffle($result);

    return $result;
}


Answer 8:

我希望这会帮助别人:

        $limit = $editForm->get('numberOfQuestions')->getData();
        $sql = "Select * from question order by RAND() limit $limit";

        $statement = $em->getConnection()->prepare($sql);
        $statement->execute();
        $questions = $statement->fetchAll();

注意这里的表的问题是一个的appbundle:问题的实体。 相应地更改的细节。 问题的数量从编辑的形式拍摄,请务必检查表单生成器的变量,并相应地使用。



Answer 9:

@克日什托夫的解决方案是最好恕我直言这里,但RAND()是大型查询速度很慢,所以我更新@ Krysztof的解决方案,得到较少的“随机”的结果,但他们仍然足够随机。 通过这个答案的启发https://stackoverflow.com/a/4329492/839434 。

 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'); # sql query $sql = " SELECT * FROM {$table} WHERE id >= FLOOR(1 + RAND()*( SELECT MAX(id) FROM {$table}) ) LIMIT ? "; # make query return $this->getEntityManager() ->createNativeQuery($sql, $rsm) ->setParameter(1, $amount); } } 


Answer 10:

也许最简单的(但不一定是最聪明的)的方式来得到一个对象的结果尽快在你的仓库类将实现这一点:

public function findOneRandom()
{
    $className = $this->getClassMetadata()->getName();

    $counter = (int) $this->getEntityManager()->createQuery("SELECT COUNT(c) FROM {$className} c")->getSingleScalarResult();

    return $this->getEntityManager()

        ->createQuery("SELECT ent FROM {$className} ent ORDER BY ent.id ASC")
        ->setMaxResults(1)
        ->setFirstResult(mt_rand(0, $counter - 1))
        ->getSingleResult()
    ;
}


Answer 11:

对我来说,最有用的方法是创建两个数组在那里我说,订单类型和实体的不同属性。 例如:

    $order = array_rand(array(
        'DESC' => 'DESC',
        'ASC' => 'ASC'
    ));

    $column = array_rand(array(
        'w.id' => 'w.id',
        'w.date' => 'w.date',
        'w.name' => 'w.name'
    ));

你可以像标准添加更多的条目数组$列。

之后,你可以建立学说加$柱和$订单里面查询 - >排序依据。 例如:

$query = $qb->select('w')
->from('DbEntities\Entity\Word', 'w')
->where('w.indictionary = 0 AND w.frequency > 3')
->orderBy($column, $order)
->getQuery()
->setMaxResults(100);

通过这种方式提高了我的应用程序的性能。 我希望这可以帮助别人。



Answer 12:

首先从数据库表中获取的MAX值,然后用这个作为PHP偏移,即$偏移量= mt_rand(1,$ maxId)



Answer 13:

我知道这是一个老问题。 但我用以下解决方案来获得随机行。

使用EntityRepository方法:

public function findOneRandom()
{
    $id_limits = $this->createQueryBuilder('entity')
        ->select('MIN(entity.id)', 'MAX(entity.id)')
        ->getQuery()
        ->getOneOrNullResult();
    $random_possible_id = rand($id_limits[1], $id_limits[2]);

    return $this->createQueryBuilder('entity')
        ->where('entity.id >= :random_id')
        ->setParameter('random_id', $random_possible_id)
        ->setMaxResults(1)
        ->getQuery()
        ->getOneOrNullResult();
}


Answer 14:

只需添加以下内容:

->orderBy('RAND()')


文章来源: How to select randomly with doctrine