From SQL to DQL - php

I want to change this SQL query : (i'm using a bundle)
(Evenement is an entity and evenement_evenement is the result of self-referencing many to many of evenement)
SELECT *
FROM evenement e
natural JOIN evenement_evenement ee
WHERE e.id = ee.evenement_source
AND e.id = 3
Into DQL. For now I have this :
public function findAllEventAssociateByEvent($idEvent){
$qb = $this->createQueryBuilder('e');
$qb->add('select', 'e');
$qb->from('Bundle:Evenement', 'e2');
$qb->where('e = :evenement');
$qb->andWhere('e2 in e.evenements');
$qb->setParameter('evenement', $idEvent);
return $qb;
//select * from evenement e NATURAL join evenement_evenement ee where e.id = ee.evenement_source and e.id = $idEvent
}
And i have this :
$eventAssocies = $em->getRepository('Bundle:Evenement')->findAllEventAssociateByEvent($id)->getQuery()->getResult();
But it's not working, i have an error in my "andWhere", but I don't know why...

I think you misunderstood some stuff, I reckon you query should more look like this:
public function findAllEventAssociateByEvent($idEvent){
$qb = $this->createQueryBuilder('e')
->join('e.evenement_evenement', 'e2')
->where('e = :evenement')
->setParameter('evenement', $idEvent);
return $qb;
}
The join will do what you were trying to do with your AndWhere I reckon

You cannot use andWhere like that, you have to treat it like you treated your where clause. Declare a parameter, and later on, set it. From what I understand, you'd need to use a subquery for that e.evenements part. Whatever you expect to be in e.evenements part, extract it to a variable, e.g: $evenements and do the following:
$qb->andWhere('e2 IN (:evenements)')
->setParameter('evenements', $evenements, Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
Assuming $evenements is an array. If it's a string, you can explode() it for example.
If you are looking for a quick solution, try this:
$qb = $this->createQueryBuilder('e')
->select('e.id')
->where('e.id = :evenement')
->setParameter('evenement', $idEvent);
$evenementsIds = $qb->getQuery()->getResult(); // This will get you an array of ID's
$qb2 = $this->createQueryBuilder('e2')
->where('e2.id IN (:evenements)')
->setParameter('evenements', $evenementsIds, Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
$result = $qb2->getQuery()->getResult();

Related

Build a query inside another with querybuilder?

I got 2 tables User and Group; each object Group got an array members[] that points to some instances of User.
I need to build this same query with QueryBuilder :
SELECT (users instances) FROM User
WHERE (users instances) IN (SELECT Group.members from Group WHERE group.id = $someId)
How can I achieve that?
You have to make 2 querybuilders:
$qb2 = $this->em->createQueryBuilder('group')
->select('group.members')
->where('group.id = $someId');
$qb = $this->em->createQueryBuilder('user')
->select(user instances)
-where($qb->expr()->in('user instances', $qb2->getDQL());
it will give you the idea how it works. Of course you have to adjust this code to yours.
Improving #Eimsas Answer it could be:
$em = $this->getEntityManager();
$qb2 = $em->createQueryBuilder('group')
->select('group.members')
->where('group.id = $someId');
$qb = $em->createQueryBuilder('user');
$query = $qb->select(user instances)
->where($qb->expr()->in('user instances', $qb2->getDQL());
$result = $query->getQuery->getResult();

How to do a LEFT JOIN ON OR in Doctrine

I'm using Doctrine's querybuilder in Symfony2 to create a query to fetch entities.
I'm trying to get this result in MySQL :
SELECT u0_.id AS id0
FROM user u0_
LEFT JOIN rva_victims r3_ ON u0_.id = r3_.user_id
INNER JOIN rva r1_ ON r1_.id = r3_.rva_id or u0_.id = r1_.declarant_id
I've tried both ON and WITH conditionType in $qb->join(), but nothing work.
Any ideas to solve my problem?
The solution should be pretty straightforward. In your case it should look like this, assuming you're in the repository class:
$this
->createQueryBuilder('u')
->leftJoin(Victims::class, 'v', Query\Expr\Join::WITH, 'v.user = u.id')
->join(Rva::class, 'r', Query\Expr\Join::WITH, 'r.id = v.rva OR u.id = r.declarant');
This should work fine, I am just assuming the class names right now. Please also take in account that all the conditions are done on class attribute names (DQL), not column names.
You can do this by creating a query builder in entity repository
$qb = $this->createQueryBuilder('u')
->leftJoin('yourbundle:Entityname', 'ye', 'WITH', 'u0_.id = r3_.user_id')
->innerJoin('yourbuncle:entityname', 'yen', 'WITH', 'r1_.id = r3_.rva_id', 'OR', 'u0_.id = r1_.declarant_id');

How to use "distinct on" with doctrine?

I try to use "distinct on" with doctrine but I get the following error:
Error: Expected known function, got 'on'
class Report extends EntityRepository
{
public function findForList() {
$queryBuilder = $this->createQueryBuilder('r');
$queryBuilder->select('distinct on (r.parentId)')
->orderBy('r.parentId')
->orderBy('r.date', 'DESC');
return $queryBuilder->getQuery()->getResult();
}
}
How could I implement the following query?
select distinct on (r.parent_id)
r.parent_id,
r.id,
r.name
from frontend.report r
order by r.parent_id, r.date desc;
Apparently it doesn't seem possible to do this with the query builder. I tried to rewrite my query in different ways:
select * from frontend.report r
where
r.id in (
select distinct
(select r3.id from frontend.report r3
where r3.parent_id = r.parent_id
order by r3.date desc limit 1) AS id
from frontend.report r2);
But doctrine doesn't support LIMIT:
public function findForList() {
$qb3 = $this->_em->createQueryBuilder();
$qb3->select('r3.id')
->from('MyBundle:frontend\report', 'r3')
->where('r3.parentId = r2.parentId')
->orderBy('r3.date', 'DESC')
//->setMaxResults(1)
;
$qb2 = $this->_em->createQueryBuilder();
$qb2->select('(' . $qb3->getDql() . ' LIMIT 1)')
->from('MyBundle:frontend\report', 'r2')
->distinct(); // groupBy('r2.parentId')
$queryBuilder = $this->createQueryBuilder('r');
$queryBuilder->where(
$queryBuilder->expr()->in('rlt.id', $qb2->getDql())
);
return $queryBuilder->getQuery()->getResult();
}
I think the only solution is to use native SQL queries.
This response is for someone that yet looking for the solution in similar cases.
If you need a sample "DISTINCT" you can use:
$queryBuinder->select('parentId')
->distinct('parentId');
but if you want a "DISTINCT ON" you should use Native SQL instead of Query Builder, check out the manual here: Doctrine Native SQL
Just remove the on word :
$queryBuilder->select('distinct r.parentId')
->orderBy('r.parentId')
->orderBy('r.date', 'DESC');

Sub-queries ActiveRecord Yii

Is it possible to make sub-queries in ActiveRecord in Yii?
i have a query like this:
select * from table1
where table1.field1 in (select table2.field2 from table2)
i'm currently using the fallowing code:
object1::model()->findAll(array('condition'=>'t.field1 in (select table2.field2 from table2)'))
[Edit]
i would like to know if there is a manner to construct the sub-query without using SQL, and without using joins.
Is there any solution ?
and thanks in advance.
First find doublets by db fields:
$model=new MyModel('search');
$model->unsetAttributes();
$criteria=new CDbCriteria();
$criteria->select='col1,col2,col3';
$criteria->group = 'col1,col2,col3';
$criteria->having = 'COUNT(col1) > 1 AND COUNT(col2) > 1 AND COUNT(col3) > 1';
Get the subquery:
$subQuery=$model->getCommandBuilder()->createFindCommand($model->getTableSchema(),$criteria)->getText();
Add the subquery condition:
$mainCriteria=new CDbCriteria();
$mainCriteria->condition=' (col1,col2,col3) in ('.$subQuery.') ';
$mainCriteria->order = 'col1,col2,col3';
How to use:
$result = MyModel::model()->findAll($mainCriteria);
Or:
$dataProvider = new CActiveDataProvider('MyModel', array(
'criteria'=>$mainCriteria,
));
Source: http://www.yiiframework.com/wiki/364/using-sub-query-for-doubletts/
No, there is not a way to programmatically construct a subquery using Yii's CDbCriteria and CActiveRecord. It doesn't look like the Query Builder has a way, either.
You can still do subqueries a few different ways, however:
$results = Object1::model()->findAll(array(
'condition'=>'t.field1 in (select table2.field2 from table2)')
);
You can also do a join (which will probably be faster, sub-queries can be slow):
$results = Object1::model()->findAll(array(
'join'=>'JOIN table2 ON t.field1 = table2.field2'
);
You can also do a direct SQL query with findAllBySql:
$results = Object1::model()->findAllBySql('
select * from table1 where table1.field1 in
(select table2.field2 from table2)'
);
You can, however, at least provide a nice AR style interface to these like so:
class MyModel extends CActiveRecord {
public function getResults() {
return Object1::model()->findAll(array(
'condition'=>'t.field1 in (select table2.field2 from table2)')
);
}
}
Called like so:
$model = new MyModel();
$results = $model->results;
One interesting alternative idea would be to create your subquery using the Query Builder's CDbCommand or something, and then just pass the resulting SQL query string into a CDbCritera addInCondition()? Not sure if this will work, but it might:
$sql = Yii::app()->db->createCommand()
->select('*')
->from('tbl_user')
->text;
$criteria->addInCondition('columnName',$sql);
You can always extend the base CDbCriteria class to process and build subqueries somehow as well. Might make a nice extension you could release! :)
I hope that helps!
I know this an old thread but maybe someone (like me) still needs an answer.
There is a small issues related to the previous answers. So, here is my enhancement:
$model=new SomeModel();
$criteria=new CDbCriteria();
$criteria->compare('attribute', $value);
$criteria->addCondition($condition);
// ... etc
$subQuery=$model->getCommandBuilder()->createFindCommand($model->getTableSchema(),$criteria)->getText();
$mainCriteria=new CDbCriteria();
$mainCriteria->addCondition($anotherCondition);
// ... etc
// NOW THIS IS IMPORTANT
$mainCriteria->params = array_merge($criteria->params, $mainCriteria->params);
// Now You can pass the criteria:
$result = OtherModel::model()->findAll($mainCriteria);

Doctrine: Convert a createQuery query to createQueryBuilder

This is the current query that I have, and it works fine:
$q = $this->_em->createQuery("SELECT s FROM app\models\Sub s
LEFT JOIN s.case c
WHERE s.type LIKE '%$type'
AND c.id = '$id'");
foreach ($q->getResult() as $row) {
$results[$row->getId()] = $row;
}
I want to convert this to the QueryBuilder API structure, this is what I have so far, but it's not working correctly. (And I need the results as the same format as above).
$q = $this->_em->createQueryBuilder();
$q->add('select', 's')
->add('from', 'app\models\Sub s')
->add('leftJoin', 's.case c')
->add('where', 's.type LIKE :type')
->add('where', 'c.id = :case');
->setParameter('type', "%$type");
->setParameter('case', $id);
And again, this isn't working properly, and I don't know how to get the results in the same format as above. Thanks!
Close, but no cigar. You'll need to learn how to use the Expr classes that comes with Doctrine in order to create the correct WHERE clause.
http://www.doctrine-project.org/docs/orm/2.1/en/reference/query-builder.html#expr-classes
In the example you provided, you are actually aiming for something like this (not tested):
$q->add('select', 's')
->add('from', 'app\model\Sub s')
->add('leftJoin', 's.case c')
->add('where', $q->expr()->andX($q->expr()->like('s.type', ':type'), $q->expr()->eq('case', ':case')))
->setParameter('type', "%$type")
->setParameter('case', $id);
As your WHERE clause gets more complicated, so will the nesting of expressions.

Categories