40

これが私のデータベースにいくつかの単語を問い合わせる方法です

$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の後にオフセットを追加できませんでした。

これをどのように達成できるか考えていますか?

4

13 に答える 13

48

Doctrine チームはこの機能を実装するつもりはありません

問題にはいくつかの解決策があり、それぞれに独自の欠点があります。

  • カスタム数値関数を追加します: このDQL RAND() 関数
    を参照してください (一致する行がたくさんある場合は遅くなる可能性があります)
  • ネイティブ クエリ を使用します
    (個人的にはこの解決策を避けようとしていますが、これは維持するのが難しいことがわかりました)。
  • 最初に生の SQL クエリを発行していくつかの ID をランダムに取得し、次に DQL を使用してWHERE x.id IN(?)、ID の配列をパラメーターとして渡すことにより、関連付けられたオブジェクトを読み込みます。
    このソリューションには 2 つの個別のクエリが含まれますが、最初のソリューションよりも優れたパフォーマンスが得られる可能性があります (既存の他の生の SQL 手法はORDER BY RAND()、ここでは詳しく説明しません。この Web サイトでいくつかの優れたリソースを見つけることができます)。
于 2012-05-26T00:33:28.363 に答える
44

次の手順を実行します:

プロジェクトで新しいクラスを次のように定義します。

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()'); //Missing curly brackets
于 2014-12-22T14:38:51.687 に答える
40

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

Doctrine ORM 2.6.x-dev でテストすると、実際に次のことができます。

->orderBy('RAND()')
于 2016-12-04T14:15:12.417 に答える
9

または、これを行うこともできます -->

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

もちろん、多くのレコードがある場合、これは非常に非効率になるため、注意して使用してください。

于 2013-02-16T13:01:32.087 に答える
7

リポジトリを使用しないのはなぜですか?

<?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);
    }
}
于 2016-08-30T09:40:37.583 に答える
0

シャッフルはクエリ (配列) の結果に対して実行できますが、シャッフルはランダムに選択しません。

エンティティからランダムに選択するには、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;
}
于 2015-09-05T08:35:10.387 に答える
0

これが他の人に役立つことを願っています:

        $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:Question エンティティであることに注意してください。それに応じて詳細を変更します。質問の数は編集フォームから取得されます。フォーム ビルダーの変数を確認し、それに応じて使用してください。

于 2016-08-11T20:10:03.570 に答える
-7

以下を追加するだけです。

->orderBy('RAND()')
于 2016-01-20T15:07:05.277 に答える