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;
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();
This is a search function that returns each member with their most recent year registered.
I got it working with a DB::raw() call. But can't get it working with the query builder.
Working Code:
$query = DB::table('membership as m');
$query->join(
DB::raw(
'(SELECT my.*
FROM membership_years my
INNER JOIN (
SELECT member_id,MAX(membership_year) AS max_my
FROM membership_years
GROUP BY member_id
) my2
ON my.member_id = my2.member_id
AND my.membership_year = my2.max_my
) my'
)
,'m.id','=','my.member_id');
My attempt on query builder code:
$query = DB::table('membership as m');
$query->join('membership_years as my',
function($j1){
$j1->join('membership_years as my2',
function($j2){
$j2->where('my.membership_year','=','MAX(my2.membership_year)')
->on('my.member_id','=','my2.member_id');
}
)->on('m.id','=','my.member_id');
}
);
The resulting error is:
Call to undefined method Illuminate\Database\Query\JoinClause::join()
I'm not sure if this is because the $j2 doesn't have access to the join method anymore?
Raw MySQL query:
SELECT my.membership_year,m.*
FROM membership AS m
INNER JOIN
(
SELECT my1.*
FROM membership_years my1
INNER JOIN
(
SELECT member_id,MAX(membership_year) AS max_my
FROM membership_years
GROUP BY member_id
) my2
ON my1.member_id = my2.member_id
AND my1.membership_year = my2.max_my
) my
ON m.id = my.member_id
ORDER BY m.id ASC
Way 1. You can write part of the query with builder:
$query = DB::table('membership as m')
->select('my.membership_year', 'm.*')
->join(DB::raw('(
SELECT my1.*
FROM membership_years my1
INNER JOIN (
SELECT member_id, MAX(membership_year) AS max_my
FROM membership_years
GROUP BY member_id
) my2
ON my1.member_id = my2.member_id
AND my1.membership_year = my2.max_my
) my'),
'm.id', '=', 'my.member_id')
->orderBy('m.id');
Way 2. Also you can write subqueries and use toSql() method:
$sub1 = DB::table('membership_years')
->select('member_id', DB::raw('MAX(membership_year) AS max_my'))
->groupBy('member_id');
$sub2 = DB::table('membership_years as my1')
->select('my1.*')
->join(DB::raw('(' . $sub1->toSql() . ') my2'),
function ($join) {
$join
->on('my1.member_id', '=', 'my2.member_id')
->on('my1.membership_year', '=', 'my2.max_my');
});
$query = DB::table('membership as m')
->select('my.membership_year', 'm.*')
->join(DB::raw('(' . $sub2->toSql() . ') my'), 'm.id', '=', 'my.member_id')
->orderBy('m.id');
I needed a result with Group By three columns and the SQL works perfectly without any issue. I'm facing the issue when I use it in the CodeIgniter framework; it doesn't execute the query. My Code and SQL are as follows.
Code
$this->db->select(['trk.userid AS user_id', 'scr.course AS course_id'])
->from('mdl_scorm scr')
->join('mdl_scorm_scoes_track trk', 'scr.id = trk.scormid', 'inner')
->join('mdl_course_modules mcs', 'mcs.instance = scr.id', 'inner')
->where_in('trk.value', ['completed','incomplete','passed'])
->group_by(['scr.course', 'trk.userid', 'trk.scormid'])
->order_by('trk.userid', 'DESC');
SQL
SELECT `trk`.`userid` AS user_id, `scr`.`course` AS course_id
FROM (`mdl_scorm` scr)
INNER JOIN `mdl_scorm_scoes_track` trk ON `scr`.`id` = `trk`.`scormid` INNER JOIN `mdl_course_modules` mcs ON `mcs`.`instance` = `scr`.`id`
WHERE `trk`.`value` IN ('completed', 'incomplete', 'passed')
GROUP BY `scr`.`course`, `trk`.`userid`, `trk`.`scormid`
ORDER BY `trk`.`userid` DESC LIMIT 0,100;
This works fine when the group_by has only two columns, like,
->group_by(['scr.course', 'trk.userid'])
What could be the reason?
In codeigniter group_by() works with two fields only.
$this->db->group_by()
Permits you to write the GROUP BY portion of your query:
$this->db->group_by(array("title", "date")); // Produces: GROUP BY title, date
CI 3 group_by()
Edit 01
$query=$this->db->query("
SELECT `trk`.`userid` AS user_id, `scr`.`course` AS course_id
FROM `mdl_scorm` scr
INNER JOIN `mdl_scorm_scoes_track` trk
ON `scr`.`id` = `trk`.`scormid`
INNER JOIN `mdl_course_modules` mcs
ON `mcs`.`instance` = `scr`.`id`
WHERE `trk`.`value` IN ('completed', 'incomplete', 'passed')
GROUP BY `scr`.`course`, `trk`.`userid`, `trk`.`scormid`
ORDER BY `trk`.`userid`
DESC LIMIT 0,100;");
$result = $query->result_array();
return $result;
Consider a raw query in the model.
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class xyz_model extends CI_Model{
function __construct()
{
// Call the Model constructor
parent::__construct();
}
function get_this_thing($month,$year)
{ $myQuery="SELECT `trk`.`userid` AS user_id, `scr`.`course` AS course_id
FROM `mdl_scorm` scr
INNER JOIN `mdl_scorm_scoes_track` trk
ON `scr`.`id` = `trk`.`scormid`
INNER JOIN `mdl_course_modules` mcs
ON `mcs`.`instance` = `scr`.`id`
WHERE `trk`.`value` IN ('completed', 'incomplete', 'passed')
GROUP BY `scr`.`course`, `trk`.`userid`, `trk`.`scormid`
ORDER BY `trk`.`userid`
DESC LIMIT 0,100;";
$query = $this->db->query($myQuery);
$result = $query->result();
return $result;
}
}
You can also pass an array of multiple values as well:
$this->db->group_by(array("title", "date")); // Produces: GROUP BY title, date
Source link
use result array instead of the result like
return $query->result_array();
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();
I have a function that creates a query to my db, like this:
public function getList($u, $t, $ls, $lf) {
return $this->getEntityManager()
->createQuery('
SELECT
o,
u,
g,
r,
t,
p
FROM GameShelfUsersBundle:Own o
LEFT JOIN o.user u
LEFT JOIN o.game g
LEFT JOIN o.rate r
LEFT JOIN o.typo t
LEFT JOIN o.platforms p
WHERE u.id = :user
AND o.typo = :type
ORDER BY o.updated DESC
')
->setParameters(array(
'user' => $u,
'type' => $t
))
->setMaxResults($lf)
->setFirstResult($ls)
->getResult();
}
My problem is, how to set :type to be not in? I mean, I wanted to use it like this:
$type = '!= 1'
...
AND o.typo :type
...
'type' => $type
But it didn't worked at all. Using $type = -1 doesn't help either. Is there any way, other than creating if/else statement and duplicating query?
Why don't you use a query builder??
In that way you can easily customize your query, depending on some condition.
This is an example:
$q = $this
->createQueryBuilder('foo')
->select('foo')
->leftJoin('foo.bar', 'foobar')
->leftJoin('foobar.bar', 'foobarbar')
;
if($myVar > 0)
{
$q->where('foobarbar.var = :myVar');
}
else
{
$q->where('foobarbar.var = :staticValue');
}
[...]
Remember to call return $q->getResult(); at the end