データベースにいくつかの単語を問い合わせる方法は次のとおりです
$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ランドがドクトリンでサポートされていないため、代わりに主キーをランダム化できます。ただし、検索条件と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の後にオフセットを追加できませんでした。
これをどのように達成できるか考えていますか?
Doctrine team この機能を実装する意思はありません 。
問題にはいくつかの解決策があり、それぞれに欠点があります。
WHERE x.id IN(?)
を使用して関連オブジェクトを読み込みます。ORDER BY Rand()
が存在するので、ここでは詳しく説明しません。このWebサイトでいくつかの優れたリソースを見つけることができます。次の手順を実行します:
プロジェクトで新しいクラスを次のように定義します。
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');
Hassan Magdy Saad suggested に沿って、人気のある 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()')
または、これを行うことができます->
$words = $em->getRepository('Entity\Word')->findAll();
shuffle($words);
もちろん、多くのレコードがある場合、これは非常に非効率的であるため、注意して使用してください。
Doctrine 2はORDER BY Rand()をサポートしていませんが、 this この問題の修正を含む記事が見つかりました。
リポジトリを使用しない理由
<?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);
}
}
私にとって、最も便利な方法は、2つの配列を作成することでした。ここで、注文タイプとエンティティの異なるプロパティを言います。例えば:
$order = array_Rand(array(
'DESC' => 'DESC',
'ASC' => 'ASC'
));
$column = array_Rand(array(
'w.id' => 'w.id',
'w.date' => 'w.date',
'w.name' => 'w.name'
));
基準のような配列$ columnにさらにエントリを追加できます。
その後、Doctrineに$ columnと$ orderを-> orderByに追加してクエリを作成できます。例:
$query = $qb->select('w')
->from('DbEntities\Entity\Word', 'w')
->where('w.indictionary = 0 AND w.frequency > 3')
->orderBy($column, $order)
->getQuery()
->setMaxResults(100);
これにより、アプリケーションのパフォーマンスが向上しました。これが誰かの助けになることを願っています。
最初にDBテーブルからMAX値を取得し、これをPHPつまり$ offset = mt_Rand(1、$ maxId)のオフセットとして使用します
これは古い質問です。ただし、次のソリューションを使用してランダムな行を取得しました。
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();
}
@Krzysztofのソリューションはここでは最高ですが、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);
}
}
1つのobjectの結果を取得する最も簡単な(ただし、必ずしも最もスマートではない)方法は、ASAPをリポジトリクラスに実装することです。
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()
;
}
これが他の人に役立つことを願っています:
$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 Entityであることに注意してください。それに応じて詳細を変更します。質問の数は編集フォームから取得されます。フォームビルダーの変数を確認し、それに応じて使用してください。
照会(配列)の結果に対してシャッフルを実行できますが、シャッフルはランダムに選択しません。
エンティティからランダムに選択するために、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;
}