How to do this query in Doctrine 2 QueryBuilder:
SELECT AVG(x.distance) avg_distance FROM (SELECT r.* FROM result r WHERE r.place_id = ? GROUP BY r.place_id ORDER BY r.id DESC LIMIT 100
I try this:
$dql = $qb
->select('r.*')
->from('CoreBundle:Result', 'r')
->where('r.place = :place')
->orderBy('r.id', 'DESC')
->setMaxResults(100)
->setParameter('place', $place)
->getDQL()
;
$result = $qb
->select('AVG(x.distance) avg_distance')
->from($dql, 'x')
->getQuery()
->getArrayResult();
but not work
SELECT r.* FROM': Error: Class 'SELECT' is not defined.
$sql = "SELECT AVG(x.distance) avg_distance FROM (SELECT r.* FROM result r WHERE r.place_id = :place_id ORDER BY r.id DESC LIMIT 100) x ";
$stmt = $this->em->getConnection()->prepare($sql);
$stmt->bindValue(':place_id', $place->getId());
$stmt->execute();
return $stmt->fetch();
Related
Hello i am trying to rewrite ZF query builder into doctrine ORM.
Here IS mine old Zend framework query.
$dependent = new Zend_Db_Expr('if(br.billing_rate = \'dependent\',(SELECT COUNT(*) FROM childcare_billing_rule_price AS p WHERE p.id < brp.id AND p.childcare_billing_rule_id = brp.childcare_billing_rule_id),0)');
$select = $this
->select()->setIntegrityCheck(false)
->from(array('brg' => 'childcare_billing_rule_group'), array())
->joinInner(array('br' => 'childcare_billing_rule'), 'br.id = brg.billing_rule_id', array('*', 'dependent' => $dependent))
->join(array('brp' => 'childcare_billing_rule_price'), 'br.id = brp.childcare_billing_rule_id', array('age_from', 'age_to', 'default_rate' => 'rate'))
->where('is_default != 1')
->where('br.billing_type in (\'' . implode('\',\'', array(self::BILLING_TYPE_PER_DAY, self::BILLING_TYPE_PER_HOUR, self::BILLING_TYPE_PER_UNLIMITED, self::BILLING_TYPE_PER_RESERVATION)) . '\')')
->where('brg.group_id IN (?)', $groupId)
->group('brp.id')
->having('dependent <= ?', $dependentLevel)
->order('dependent desc')
->order('brp.rate');
And here it is SQL row value
SELECT `br`.*,
if (br.billing_rate = 'dependent',
(SELECT COUNT(*) FROM childcare_billing_rule_price AS p WHERE p.id < brp.id AND p.childcare_billing_rule_id = brp.childcare_billing_rule_id),
0) AS `dependent`,
`brp`.`age_from`,
`brp`.`age_to`,
`brp`.`rate` AS `default_rate`
FROM `childcare_billing_rule_group` AS `brg`
INNER JOIN `childcare_billing_rule` AS `br` ON br.id = brg.billing_rule_id
INNER JOIN `childcare_billing_rule_price` AS `brp` ON br.id = brp.childcare_billing_rule_id
WHERE (is_default != 1)
AND (br.billing_type in ('Per Day','Per Hour','Unlimited','Per Reservation'))
AND (brg.group_id IN (103))
AND ((brp.age_from = 0 AND brp.age_to = 0) || 3.1666666666667
BETWEEN brp.age_from AND brp.age_to)
GROUP BY `brp`.`id` HAVING (dependent <= '0')
ORDER BY `dependentw` desc,
`brp`.`rate` ASC
I am not sure how to implement this sub query
new Zend_Db_Expr('if(br.billing_rate = \'dependent\',(SELECT COUNT(*) FROM childcare_billing_rule_price AS p WHERE p.id < brp.id AND p.childcare_billing_rule_id = brp.childcare_billing_rule_id),0)');
My code so far
$subQuery = $subQueryBuilder
->select('if (br.billing_rate = 'dependent',
(SELECT COUNT(*) FROM childcare_billing_rule_price AS p WHERE p.id < brp.id AND p.childcare_billing_rule_id = brp.childcare_billing_rule_id)')
->getSQL();
$queryBuilder->select($alias)
->addSelect($subQuery)
->innerJoin(ChildcareBillingRule::class, 'br', Join::WITH, 'br.id = childcare_billing_rule_group.childcareBillingRule')
->innerJoin(ChildcareBillingRulePrice::class, 'brp', Join::WITH, 'br.id = brp.childcareBillingRule')
->where("br.billingType in (:billingTypes)")
->andWhere( 'br.isDefault != :isDefault')
->andWhere( 'childcare_billing_rule_group.groupId in (:groupId)')
->setParameter('groupId', [103])
->setParameter('isDefault', 1)
->setParameter('billingTypes', ['Per Hour', 'Per Reservation', 'Per Day', 'Unlimited'])
->having('dependent <= ?', $dependentLevel')
->groupBy('brp.id')
->orderBy('brp.rate') ;
->getQuery()->getSingleResult();
so i am trying to add sub query with addSelect but not sure is this the right way? Any Help or idea is appreciated? Tnx
in short instead of ->getSQL() you should use ->getDQL().
Yours code will be like:
$dql = $this->createQueryBuilder()
->select('count(id)')
->from({Class::FQDN}, {ALIAS})
->getDQL();
$result = $this->createQueryBuilder()
->select({SECOND_ALIAS})
->from({SecondClass::FQDN}, {SECOND_ALIAS})
->where((new \Expr())->gt('{SECOND_ALIAS}.cnt', $dql))
->getQuery()
->getResult();
Here is my code:
$qb = $this->_em
->createQueryBuilder();
$query = $qb->select('COUNT(food) as cnt')
->from(Food::class, 'food')
->groupBy('cnt')
->getQuery()->getSQL();
However my expectation like the following query:
SELECT COUNT(f0_.food_id) AS sclr_0 FROM foods f0_ WHERE (f0_.deleted_at IS NULL) GROUP BY sclr_0
The result looks like:
SELECT COUNT(f0_.food_id) AS sclr_0 FROM foods f0_ WHERE (f0_.deleted_at IS NULL) GROUP BY f0_.food_id
Any suggestion?
You'll need to use your query as a subquery, Id do this in raw SQL, but you can get the idea from:
$qb = $this->_em
->createQueryBuilder();
$query = $qb->select('COUNT(food) as cnt')
->from(Food::class, 'food')
->groupBy('cnt')
->getQuery()->getSQL();
$qb2 = $this->_em
->createQueryBuilder();
$query2 = $qb->select('sclr_0')
->from('('.$query.')', 'cnt')
->groupBy('sclr_0 ')
->getQuery()->getSQL();
subquery and querybuilder in my project but result is error
my dql code is
$subQb = $em->createQueryBuilder();
$subquery = $subQb->select('COUNT(v.id)')
->from('AdminBundle:Visitsite', 'v')
->where('v.site = s.id')
->Andwhere('v.createdate > :date')
->getDQL();
$subQb2 = $em->createQueryBuilder();
$subquery2 = $subQb2->select('l.quantity')
->from('AdminBundle:Limitviewday', 'l')
->where($subQb2->expr()->eq('s.limitviewday', 'l.id'))
->getDQL();
$subQb3 = $em->createQueryBuilder();
$subquery3 = $subQb3->select('COUNT(i.id)')
->from('AdminBundle:Visitsite', 'i')
->where('i.site = s.id')
->Andwhere('i.createdate > :date2')
->Andwhere('i.ip = :ip')
->groupBy('i.ip')
->getDQL();
$subQb4 = $em->createQueryBuilder();
$subquery4 = $subQb4->select('ipl.quantity')
->from('AdminBundle:Iplimitview', 'ipl')
->where('s.iplimitview = ipl.id')
->getDQL();
$qb = $em->createQueryBuilder();
$query = $qb->select('s')
->from('AdminBundle:Sites', 's')
->where('s.quantity > :one')
->Andwhere('s.status = :two')
->Andwhere($qb->expr()->lt("($subquery)", "($subquery2)"))
->Andwhere($qb->expr()->lt("(COALESCE( ($subquery3),0) )", "($subquery4))"))
->setParameter('one', 1)
->setParameter('two', 1)
->setParameter('date', $date->format('Y-m-d'))
->setParameter('ip', $ip)
->setParameter('date2', $date->format('Y-m-d 00:00:00'));
$settlements = $query->getQuery()->getResult();
and my result dql is
SELECT s FROM AdminBundle:Sites s WHERE s.quantity > :one AND s.status = :two AND ((SELECT COUNT(v.id) FROM AdminBundle:Visitsite v WHERE v.site = s.id AND v.createdate > :date) < (SELECT l.quantity FROM AdminBundle:Limitviewday l WHERE s.limitviewday = l.id)) AND ((COALESCE( (SELECT COUNT(i.id) FROM AdminBundle:Visitsite i WHERE i.site = s.id AND i.createdate > :date2 AND i.ip = :ip GROUP BY i.ip),0) ) < (SELECT ipl.quantity FROM AdminBundle:Iplimitview ipl WHERE s.iplimitview = ipl.id)))
every ting is ok but my result is error
[Syntax Error] line 0, col 279: Error: Expected Literal, got 'SELECT'
Your output sql is SELECT s FROM AdminBundle:Sites but it is wrong.
correction is
SELECT *FROM AdminBundle:Sites
s is not field, should be use before FROM column name like s.quantity, s.stauts like that
Please edit your code in this like : $query = $qb->select('s') change select 's' link above instruction
I have this query
SELECT
arl_kind,
IF (tof_art_lookup.arl_kind = 2, tof_suppliers.sup_brand, tof_brands.bra_brand) AS brand,
arl_display_nr
FROM
tof_art_lookup
LEFT JOIN
tof_brands
ON
bra_id = arl_bra_id
INNER JOIN
tof_articles
ON
tof_articles.art_id = tof_art_lookup.arl_art_id
INNER JOIN
tof_suppliers
ON
tof_suppliers.sup_id = tof_articles.art_sup_id
WHERE
arl_art_id = #art_id
AND arl_kind IN (3)
ORDER BY
arl_kind,
bra_brand,
arl_display_nr limit 100;
when I execute this on phpmyadmin or in any software that has sql comand capabilities everything works and the output is as i should.
The problem appears when I try to insert this in codeigniter, and my main probles is with the if statement, I tried to insert it like this
return $query = $this->db
->SELECT('
arl_kind,
IF (tof_art_lookup.arl_kind = 2, tof_suppliers.sup_brand, tof_brands.bra_brand) AS brand,
arl_display_nr
FROM
tof_art_lookup
LEFT JOIN
tof_brands
ON
bra_id = arl_bra_id
INNER JOIN
tof_articles
ON
tof_articles.art_id = tof_art_lookup.arl_art_id
INNER JOIN
tof_suppliers
ON
tof_suppliers.sup_id = tof_articles.art_sup_id
WHERE
arl_art_id = #art_id
AND arl_kind IN (3)
ORDER BY
arl_kind,
bra_brand,
arl_display_nr limit 100')
->get();
and second option like that
return $query = $this->db
->select('ARL_KIND, IF (tof_art_lookup.arl_kind = 2, tof_suppliers.sup_brand, tof_brands.bra_brand) AS brand,ARL_DISPLAY_NR')
->from('tof_art_lookup')
->join('tof_brands','bra_id = arl_bra_id','LEFT')
->join('tof_articles','tof_articles.art_id = tof_art_lookup.arl_art_id','INNER')
->join('tof_suppliers','tof_suppliers.sup_id = tof_articles.art_sup_id','INNER')
->where('ARL_ART_ID',$id)
->where_in('ARL_KIND',array('3'))
//->where('A.ARL_DISPLAY','0')
->group_by('arl_kind','bra_brand','arl_display_nr')
->get();
both of them work but partialy without the second select option the one with the if.
Can anyone help me to fix this.
I believe your code should look like this
return $query = $this->db
->select('arl_kind, IF(tof_art_lookup.arl_kind = 2, tof_suppliers.sup_brand, tof_brands.bra_brand) AS brand,ARL_DISPLAY_NR', FALSE)
->from('tof_art_lookup')
->join('tof_brands', 'bra_id = arl_bra_id', 'LEFT')
->join('tof_articles', 'tof_articles.art_id = tof_art_lookup.arl_art_id', 'INNER')
->join('tof_suppliers','tof_suppliers.sup_id = tof_articles.art_sup_id', 'INNER')
->where('arl_art_id', $id)
->where_in('arl_kind', array('3'))
->order_by('arl_kind','bra_brand','arl_display_nr')
->limit(100)
->get();
Note: second parameter of select() method is set to FALSE and order_by() is used instead of group_by() as in your original query.
use like this
$query_string = "SELECT
arl_kind,
IF (tof_art_lookup.arl_kind = 2, tof_suppliers.sup_brand, tof_brands.bra_brand) AS brand,
arl_display_nr
FROM
tof_art_lookup
LEFT JOIN
tof_brands
ON
bra_id = arl_bra_id
INNER JOIN
tof_articles
ON
tof_articles.art_id = tof_art_lookup.arl_art_id
INNER JOIN
tof_suppliers
ON
tof_suppliers.sup_id = tof_articles.art_sup_id
WHERE
arl_art_id = #art_id
AND arl_kind IN (3)
ORDER BY
arl_kind,
bra_brand,
arl_display_nr limit 100";
$query=$this->db->query($query_string);
if ($query->num_rows () > 0) {
return $query->result_array ();
} else {
return FALSE;
}
So i have this raw SQL that i want to call via the zend framework
select t.type, t.tid,t.tname,t.cid,t.cname, ls.*
from
(
select t.type, t.id as tid, t.name as tname, c.id as cid, c.name as cname from team t
join company c on t.parent=c.id and t.type='C' and c.sector=20 and t.status='ACTIVE'
union
select t.type, t.id as tid,t.name as tname, null as cid, null as cname from team t
join sector s on t.parent=s.id and t.type='S'and s.id=20 and t.status='ACTIVE'
) t
LEFT JOIN leaguesummary ls ON ls.leagueparticipantid=t.tid AND ls.leaguetype='T'
WHERE ls.leagueid = 5
ORDER BY ls.leaguedivision asc, ls.leagueposition asc LIMIT 10;
I have my model class which extends Zend_Db_Table i've a simple method to build the SQL and query it
class Model_DbTable_LeagueSummary extends Zend_Db_Table_Abstract {
....
public function getTeamLeagueSummayBySector($sectorid,$limit=10)
{
$select = $this->select()
->setIntegrityCheck(false)
->from(array('team'=>'team'),array('type','id','name'))
->join(array('company'=>'company'),'team.parent=company.id',array())
->where('team.type="C"')
->where('team.status="ACTIVE"')
->where('company.sector=?',$sectorid);
$select2 = $this->select()
->setIntegrityCheck(false)
->from(array('team'=>'team'),array('type','id','name'))
->join(array('sector'=>'sector'),'team.parent=sector.id',array())
->where('team.type="S"')
->where('team.status="ACTIVE"')
->where('sector.id=?',$sectorid);
// manually creating the SQL string and calling Zend_Db_Table::getDefaultAdapter() directly
$STRING = sprintf("select x.*,ls.* from ( %s union %s ) x
LEFT JOIN leaguesummary ls ON ls.leagueparticipantid=x.id AND ls.leaguetype='T'
WHERE ls.leagueid = 5
ORDER BY ls.leaguedivision asc, ls.leagueposition asc LIMIT 10;",$select,$select2);
$db = Zend_Db_Table::getDefaultAdapter();
$stmt = $db->query($STRING);
$stmt->setFetchMode(Zend_Db::FETCH_OBJ);
$result = $stmt->fetchAll();
return $result;
}
This query works, but don't like the solution and wanted to refactor the code to use the Zend_DB methods more correctly. I've gotten this far
$sql = $this->select()
->setIntegrityCheck(false)
->from(array('X'=>'X'))
->union(array($select,$select2))
->joinLeft(array('leaguesummary'=>'leaguesummary'),'leaguesummary.leagueparticipantid=X.id')
->where('leaguesummary.leaguetype="T"')
->where("leaguesummary.leagueid = ?",5)
->order("leaguesummary.leaguedivision asc")
->order("leaguesummary.leagueposition asc")
->limit($limit);
return $db->fetchAll($sql);
But i get this exception. Whats wrong with the union statements?
Message: Invalid use of table with UNION
Stack trace:
#0 /home/assure/bhaa/zend/trunk/library/Zend/Db/Select.php(357): Zend_Db_Select->_join('left join', Array, 'leaguesummary.l...', '*', NULL)
#1 /home/assure/bhaa/zend/trunk/application/models/DbTable/LeagueSummary.php(175): Zend_Db_Select->joinLeft(Array, 'leaguesummary.l...')
#2 /home/assure/bhaa/zend/trunk/application/controllers/HousesController.php(110): Model_DbTable_LeagueSummary->getTeamLeagueSummayBySector('20')
#3 /home/assure/bhaa/zend/trunk/library/Zend/Controller/Action.php(513): HousesController->sectorAction()
#4 /home/assure/bhaa/zend/trunk/library/Zend/Controller/Dispatcher/Standard.php(289): Zend_Controller_Action->dispatch('sectorAction')
#5 /home/assure/bhaa/zend/trunk/library/Zend/Controller/Front.php(954): Zend_Controller_Dispatcher_Standard->dispatch(Object(Zend_Controller_Request_Http), Object(Zend_Controller_Response_Http))
#6 /home/assure/bhaa/zend/trunk/library/Zend/Application/Bootstrap/Bootstrap.php(97): Zend_Controller_Front->dispatch()
#7 /home/assure/bhaa/zend/trunk/library/Zend/Application.php(366): Zend_Application_Bootstrap_Bootstrap->run()
-- EDIT 2 --
So i added a third step and merge the two union sql statements like this
$union = $this->getDefaultAdapter()->select()->union(array($select,$select2));
$logger->info(sprintf(' (%s) ',$union));
which gives me valid SQL
2010-06-04T15:11:55+00:00 INFO (6): (SELECT `team`.`type`, `team`.`id`, `team`.`name` FROM `team` INNER JOIN `company` ON team.parent=company.id WHERE (team.type="C") AND (team.status="ACTIVE") AND (company.sector='20') UNION SELECT `team`.`type`, `team`.`id`, `team`.`name` FROM `team` INNER JOIN `sector` ON team.parent=sector.id WHERE (team.type="S") AND (team.status="ACTIVE") AND (sector.id='20'))
The next step was to integrate this union clause into the main query, I've played around with the from() clause like so
->from(array('X'=> '('.$union.')' ) )
->joinLeft(array('leaguesummary'=>'leaguesummary'),'leaguesummary.leagueparticipantid=X.id')
->where('leaguesummary.leaguetype="T"')
->where("leaguesummary.leagueid = ?",5)
->order("leaguesummary.leaguedivision asc")
->order("leaguesummary.leagueposition asc")
->limit($limit);
$logger->info(sprintf('%s',$sql));
return $this->getDefaultAdapter()->fetchAll($sql);
but it seems that when the '$union' variable to converted to a string it is somehow getting shortened, which means my SQL is invalid
SELECT `X`.*, `leaguesummary`.* FROM `(SELECT ``team```.```type``, ``team``` AS `X` LEFT JOIN `leaguesummary` ON leaguesummary.leagueparticipantid=X.id WHERE (leaguesummary.leaguetype="T") AND (leaguesummary.leagueid = 5) ORDER BY `leaguesummary`.`leaguedivision` asc, `leaguesummary`.`leagueposition` asc LIMIT 10
Any ideas?
For a query as "complicated" as yours, you may not want to do it the "Zend" way. You can use the query() function with raw SQL
$rows = $this->getAdapter()->query("
select t.type, t.tid,t.tname,t.cid,t.cname, ls.*
from
(
select t.type, t.id as tid, t.name as tname, c.id as cid, c.name as cname from team t
join company c on t.parent=c.id and t.type='C' and c.sector=20 and t.status='ACTIVE'
union
select t.type, t.id as tid,t.name as tname, null as cid, null as cname from team t
join sector s on t.parent=s.id and t.type='S'and s.id=20 and t.status='ACTIVE'
) t
LEFT JOIN leaguesummary ls ON ls.leagueparticipantid=t.tid AND ls.leaguetype='T'
WHERE ls.leagueid = 5
ORDER BY ls.leaguedivision asc, ls.leagueposition asc LIMIT 10;
");
This bug report shows the proper use for the union() function:
$selectA = $db->select()
->from(array('u' => 'user'), 'name')
->where('u.id >= 5');
$selectB = $db->select()
->from(array('u' => 'user'), 'name')
->where('u.id < 5');
$select = $db->select()
->union(array($selectA, $selectB));
Or alternatively:
$select = $db->select()
->union(array(
$db->select()
->from(array('u' => 'user'), 'name')
->where('u.id >= 5'),
$db->select()
->from(array('u' => 'user'), 'name')
->where('u.id < 5')
));
$pmSort = 'user_lname DESC';
$qry1=$this->select()
->setIntegrityCheck(false)
->from(array('team'=>'plg_team'),array('team_id','team_name','team_sprt_id','team_user_id'))
->joinInner(array('user'=>'plg_users'),'user.user_id=team_user_id',array('user_fname','user_lname','user_email'))
->where("team_id='$pmTeamID' and team_status=1 and user_status=1");
$qry2=$this->select()
->setIntegrityCheck(false)
->from(array('t'=>'plg_team'),array('team_id'))
->joinInner(array('tp'=>'plg_team_players'),'t.team_id = tp.plyr_team_id',array('plyr_id'))
->joinInner(array('rlsp'=>'plg_relationships'),'rlsp.rlsp_rsty_id = 2',array('rlsp_id'))
->joinInner(array('user'=>'plg_users'),'user.user_id = rlsp.rlsp_relation_user_id',array('user_id','user_fname','user_lname','user_email'))
->where("user.user_status=1 and t.team_status=1 and tp.plyr_status=1 and t.team_id='$pmTeamID' and rlsp.rlsp_user_id = tp.plyr_user_id");
$select = $this->select()
->setIntegrityCheck(false)
->union(array($qry1, $qry2));
$select1 = $this->select()
->setIntegrityCheck(false)
->from(array('T'=> $select ) )
->order($pmSort);
echo $select1;