以下是我在数据库中查询某些单词的方法
$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()命令。
我发现this similar问题基本上是建议的,因为在教条中不支持ORDER BY RAND,您可以随机化主键。但是,在我的情况下无法做到这一点,因为我有一个搜索条件和一个where子句,以便不是每个主键都满足这个条件。
我还发现code snippet建议您使用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之后添加偏移量。
知道如何实现这一目标吗?
答案 0 :(得分:41)
The Doctrine团队is not willing to implement this feature。
您的问题有几种解决方案,每种解决方案都有其自身的缺点:
WHERE x.id IN(?)
加载相关对象,方法是将ID数组作为参数传递。ORDER BY RAND()
之外的其他原始SQL技术,我不会在这里详述它们,你会发现一些好的本网站上的资源)。答案 1 :(得分:30)
请按照以下步骤操作:
在项目中定义一个新类:
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');
答案 2 :(得分:16)
与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()')
答案 3 :(得分:7)
或者你可以这样做 - >
$words = $em->getRepository('Entity\Word')->findAll();
shuffle($words);
当然,如果您有许多记录,这将非常低效,因此请谨慎使用。
答案 4 :(得分:5)
Doctrine 2不支持ORDER BY rand(),但我发现this文章中包含对此进行修复的问题。
答案 5 :(得分:4)
为什么不使用存储库?
<?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);
}
}
答案 6 :(得分:1)
对我来说,最有用的方法是创建两个数组,在这里我说订单类型和实体的不同属性。例如:
$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在-> orderBy内添加$ column和$ order来构建查询。例如:
$query = $qb->select('w')
->from('DbEntities\Entity\Word', 'w')
->where('w.indictionary = 0 AND w.frequency > 3')
->orderBy($column, $order)
->getQuery()
->setMaxResults(100);
这样可以提高应用程序的性能。我希望这对某人有帮助。
答案 7 :(得分:0)
可以对查询(数组)结果进行混洗,但是随机抽取不会随机选择。
为了从实体中随机选择,我更喜欢在PHP中执行此操作,这可能会减慢随机选择速度,但它允许我控制测试我正在做的事情并使最终调试更容易。
下面的示例将实体中的所有ID放入一个数组中,然后我可以将其用于&#34;随机处理&#34;在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;
}
答案 8 :(得分: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:问题实体。相应地更改详细信息。问题的数量来自编辑表单,请确保检查表单构建器的变量并相应地使用。
答案 9 :(得分:0)
@ Krzysztof的解决方案在这里是最好的恕我直言,但是RAND()在大型查询上非常慢,所以我更新了@Krysztof的解决方案,以减少&#34;随机&#34;结果,但它们仍然是随机的。灵感来自这个答案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);
}
}
答案 10 :(得分:0)
可能最简单(但不一定是最聪明)的方法来获得单个对象结果ASAP将在您的Repository类中实现它:
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()
;
}
答案 11 :(得分:0)
首先从数据库表中获取最大值,然后将其用作PHP中的偏移量,即 $ offset = mt_rand(1,$ maxId)
答案 12 :(得分:-1)
我知道这是一个老问题。但我使用以下解决方案来获取随机行。
使用 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();
}
答案 13 :(得分:-4)
只需添加以下内容:
->orderBy('RAND()')