Zend_DB union() : Zend_Db_Table_Abstract vs Zend_Db_Table::getDefaultAdapter()
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)
开发者_JS百科#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;
精彩评论