Zend DB and Conditional Case Statements
I have a zend app that displays a league table of race results. The basic process is to determine the list of events to be included, and then dynamically add a set of columns to a SQL query. My initial implementation is rather rubbish and i want to refector it. I manually build up a string of SQL and at the very end call db->fetch(). I know - crap code, but i was still learning zend and had a deadline.
public function league()
{
...
$SQL = 'SELECT rr.runner AS runnerid, ru.firstname as firstname, ru.surname as surname, ';
// get the list of events
foreach($events as $eventrow)
{
$eventTable = new Model_DbTable_Event();
$event = $eventTable->find($eventrow->event)->current();
// generate the conditional column
$sum = $this->getEventSQL($event,$division->gender);
// append to the SQL string (nasty)
$SQL = $SQL . $sum;
}
$SQL = $SQL . 'lrd.racesComplete, lrd.pointsTotal, c.name as company ';
$SQL = $SQL . 'FROM raceresult rr ';
$SQL = $SQL . 'JOIN runner ru ON rr.runner = ru.id ';
$SQL = $SQL . 'LEFT JOIN company c ON c.id = ru.company ';
$SQL = $SQL . 'JOIN race ra ON rr.race = ra.id ';
...
...
$db = Zend_Db_Table::getDefaultAdapter();
$this->view->leaguetable = $db->fetchAll($SQL);
}
// create the SUM sql statement for a specific event
// SUM(CASE rr.race WHEN 15 THEN rr.points ELSE NULL END) as Result1,
// SUM(CASE rr.race WHEN 16 THEN rr.points ELSE NULL END) as Result2,
function getEventSQL($event,$type)
{
$eventTable = new Model_DbTable_Event();
$sum_sql = 'SUM(CASE rr.race ';
foreach($races as $race)
{
$sum_sql = $sum_sql . sprintf('WHEN %d',$race->id) . ' THEN rr.points ';
}
$sum_sql = $sum_sql . sprintf('ELSE NULL END) as \'%s\',',$event->id);
return $sum_sql;
}
I know i need to use the SQL SELECT/CASE statements.
Conditional column for query based on other columns in MySQL
I want to move this logic to a class that extends Zend_Db_Table_Abstract but i'm still unsure what is the best way to conditionally control the columns that are selected. I know i can add multiple where() clauses, can the column() method be used in this scenario?
class Model_DbTable_League extends Zend_Db_Table_Abstract
{
protected $_name = 'leaguerunnerdata';
protected $_primary = 'Id';
public function leagueTable($min,$max)
{
$sql = $this->select()
->setIntegrityCheck(false)
->from(array('l'=>'league'),array('col','col2','col3'))
->where('l.league = ?',1)
->where('r.standard > ?',$min)
开发者_如何学编程 ->where('r.standard < ?',$max)
->order('l.pointsTotal DESC');
return $this->fetchAll($sql);
}
....
Any ideas/suggestions?
The perfecto answerino
$select = $this->select()->setIntegrityCheck(false)
$select->from(array('l' => 'league'), array('leagueId'=> 'id', 'name','location','competitionName','eventManager','owner' ) )
->join(array('r' => 'whateverRTableIs'),
'r.id = l.id',
array())
->where('l.league = ?',1)
->where('r.standard > ?',$min)
->where('r.standard < ?',$max)
->order('l.pointsTotal DESC');
return $this->fetchAll($select);
I figured out that i could use the 'columns()' method to dynamically add extra fields to my query, and use the Zend_Db_Expr to correctly format the specific value for the column.
$select = $this->select()
->setIntegrityCheck(false)
->from(array('raceresult'=>'raceresult'),array())
->join(array('runner'=>'runner'),'runner.id=raceresult.runner',array('id','firstname','surname'));
foreach($races as $taggedrace)
{
$select->columns(new Zend_Db_Expr(
sprintf("SUM(CASE raceresult.race WHEN %d THEN raceresult.points ELSE NULL END) as %s",
$taggedrace->raceid,$taggedrace->tag)));
}
$select->join(array('race'=>'race'),'race.id = raceresult.race',array())
->join(array('event'=>'event'),'race.event = event.id',array())
->join(array('leagueevent'=>'leagueevent'),'leagueevent.event = event.id',array())
->join(array('leaguerunnerdata'=>'leaguerunnerdata'),
'leaguerunnerdata.runner = raceresult.runner AND leaguerunnerdata.league=leagueevent.league',
array('racesComplete','pointsTotal'))
->joinLeft(array('company'=>'company'), 'company.id = runner.company',array('name'))
->where( sprintf('leaguerunnerdata.standard BETWEEN %d AND %d ',$division->min,$division->max))
->where('runner.gender= ?',$division->gender)
->where('leagueevent.league = ?',$league)
->group(array('raceresult.runner','leaguerunnerdata.racesComplete','leaguerunnerdata.pointsTotal'))
->order(array('leaguerunnerdata.pointsTotal desc'));
精彩评论