Grouping WHERE clauses with Zend_Db_Table_Abstract - zend-framework

Does anyone know of a way to group where clauses with Zend_Db? Basically I have this query
$sql = $table->select()
->where('company_id = ?', $company_id)
->where('client_email = ?', $client_email)
->orWhere('client_email_alt = ?', $client_email);
Which is giving me this:
SELECT `clients`.* FROM `clients` WHERE (company_id = '1') AND (client_email = 'email#address.com') OR (client_email_alt = 'email#address.com')
But I need it to give me this, where the OR statement is grouped:
SELECT `clients`.* FROM `clients` WHERE (company_id = '1') AND ((client_email = 'email#address.com') OR (client_email_alt = 'email#address.com'))

In order to achieve this, you have to construct the grouped clause within a single call to the where method.
If both values of conditions are the same, you can do this:
$select->where('client_email = ? OR client_email_alt = ?', $client_email)
If there are multiple placeholders within the string, the DB adapter's quoteInto method will replace all placeholders with the provided value.
If you need to group an OR with different values for each field, you have to manually quote the values. It's a bit more complex:
$select->where(
$db->quoteInto('client_email = ?', $email1) . ' OR ' . $db->quoteInto('client_email_alt = ?', $email2)
); // $db is your instance of Zend_Db_Adapter_*
// You can get it from a Zend_Db_Table_Abstract
//subclass by calling its getAdapter() method

You can use getPart() to get WHERE statement and then connect sub-queries.
$select->where('client_email = ?', $client_email)
->orWhere('client_email_alt = ?', $client_email);
$subquery = $select->getPart(Zend_Db_Select::WHERE);
$select ->reset(Zend_Db_Select::WHERE);
$select ->where('company_id = ?', $company_id)
->where(implode(' ',$subquery));

For Zend Framework Version 2, things differ a bit:
See http://framework.zend.com/apidoc/2.2/classes/Zend.Db.Sql.Predicate.Predicate.html#nest
$table->select()
->where(['company_id'=> $company_id])
->nest
->where('client_email = ?', $client_email)
->or
->where('client_email_alt = ?', $client_email)
->unnest();
works fine and feels much cleaner than the ZF1 methods.

I needed to combine AND/OR statements but including OR statements conditionally, adding them only in some cases. This solution is an adaptation of what I did, based on small modifications of the accepted answer.
$sql = $table->select()
->where('company_id = ?', $company_id);
$orWhereClauses = [];
// We could add a conditional statement to add this statement
$orWhereClauses[] = $db->quoteInto('client_email = ?', $email1);
// Same applies to this statement
$orWhereClauses[] = $db->quoteInto('client_email_alt = ?', $email2);
$sql->where(implode(" OR ", $orWhereClauses));

In first you can generate subquery, then get "WHERE" part and insert into main query
$subquery = $db->select();
$subquery->orWhere('a>10');
$subquery->orWhere('b<20');
etc..
$subquery = $subquery->getPart(Zend_Db_Select::WHERE);
$select->where(implode(' ',$subquery));

Related

Zend Db query to select all IDs

How would I write an Zend DB query to select all from the column ID?
So far I have tried:
public function getLatestUserID()
{
$ids = $this->select()
->where('id = ?');
return $ids;
}
But to no avail.
You just want the id column,
You failed to call an execute command.
try:
//assuming you are using a DbTable model
public function getLatestUserID()
{
$ids = $this->fetchAll('id');
return $ids;
}
I would do it like this, because I use the select() object for everything:
public function getLatestUserID()
{
$select = $this->select();
//I'm not sure if $this will work in this contex but you can out the table name
$select->from(array($this), array('id'));
$ids = $this->fetchAll($select);
return $ids;
}
The first two examples should return just the id column of the table, now if you actually want to query for a specific id:
public function getLatestUserID($id)
{
$select = $this->select();
$select->where('id = ?', $id);
//fetchAll() would still work here if we wanted multiple rows returned
//but fetchRow() for one row and fetchRowset() for multiple rows are probably
//more specific for this purpose.
$ids = $this->fetchRow($select);
return $ids;
}
make sure your class containing getLatestUserID does extend Zend_Db_Table_Abstract also :
$ids = $this->select()->where('id = ?'); can't work because where('id = ?'); expects an id value like where('id = ?', $id);
if what you want is the latest inserted row's Id use :
$lastInsertId = $this->getAdapter()->lastInsertId();
(however if you are using an oracle database this will not work and you should use $lastInsertId = $this->getAdapter()->lastSequenceId('USER_TABLE_SEQUENCE'); )

Zend Framework Table Relationships - select from multiple tables within app

I hope I'm asking this question in an understandable way. I've been working on an app that has been dealing with 1 table ( jobschedule ). So, I have models/Jobschedule.php, models/JobscheduleMapper.php, controllers/JobscheduleController.php, view/scripts/jobschedule/*.phtml files
So in my controller I'll do something like this:
$jobnumber = $jobschedule->getJobnum();
$jobtype = $jobschedule->getJobtype();
$table = $this->getDbTable();
public function listAction()
{
$this->_helper->layout->disableLayout();
$this->view->jobnum = $this->getRequest()->getParam( 'jobnum', false );
$this->view->items = array();
$jobschedule = new Application_Model_Jobschedule();
$jobschedule->setJobnum( $this->view->jobnum );
$mapper = new Application_Model_JobscheduleMapper();
$this->view->entries = $mapper->fetchAll ( $jobschedule );
}
and then in my mapper I I do something like:
$resultSet = $table->fetchAll($table->select()->where('jobnum = ?', $jobnumber)->where('jobtype = ?', $jobtype) );
$entries = array();
foreach ($resultSet as $row) {
$entry = new Application_Model_Jobschedule();
$entry->setJobnum($row->jobnum)
->setJobtype($row->jobtype)
->setJobdesc($row->jobdesc)
->setJobstart($row->jobstart)
->setJobend($row->jobend)
->setJobfinished($row->jobfinished)
->setJobnotes($row->jobnotes)
->setJobid($row->jobid);
$entries[] = $entry;
}
return $entries;
}
Then in my view I can manipulate $entries. Well, the problem I'm coming across now is that there is also another table called 'jobindex' that has a column in it called 'jobno'. That 'jobno' column holds the same record as the 'jobnum' column in the 'jobschedule' table. I need to find the value of the 'store_type' column in the 'jobindex' table where jobindex.jobno = joschedule.jobnum ( where 1234 is the jobno/jobnum for example ). Can someone please help me here? Do I need to create a jobindex mapper and controller? If so, that's done ... I just don't know how to manipulate both tables at once and get the record I need. And where to put that code...in my controller?
If I understand you correctly this is the SQL query you need to extract the data from database:
SELECT `jobschedule`.* FROM `jobschedule` INNER JOIN `jobindex` ON jobindex.jobno = jobschedule.jobnum WHERE (jobindex.jobtype = 'WM')
Assembling this SQL query in Zend would look something like this:
$select->from('jobschedule', array('*'))
->joinInner(
'jobindex',
'jobindex.jobno = jobschedule.jobnum',
array())
->where('jobindex.jobtype = ?', $jobtype);
Let us know if that's what you are looking for.
If I'm understanding you correctly, you'll want to join the 'jobindex' table to the 'jobschedule' table.
...
$resultSet = $table->fetchAll(
$table->select()->setIntegrityCheck(false)
->from($table, array('*'))
->joinLeft(
'jobindex',
'jobindex.jobno = jobschedule.jobnumber',
array('store_type'))
->where('jobnum = ?', $jobnumber)
->where('jobtype = ?', $jobtype)
->where('jobindex.store_type = ?', $_POST['store_num'])
);
....
Depending on how 'jobschedule' is related to 'jobindex', you may want an inner join (joinInner()) instead.
The setIntegrityCheck(false) disables referential integrity between the tables, which is only important if you are writing to them. For queries like this one, you can just disable it and move on (else it will throw an exception).

Zend Db joinLeft with parameterized value

I need to joinLeft within Zend_Db ala:
$select->joinLeft(array('ATAG' => 'ad_tags'),
array('ADM.id = ATAG.ad_id AND ADM.site_id = ATAG.site_id AND ATAG.tag_id = ?', $input_vars['tag']),
array('tag_id'))
->order('ATAG.tag_id DESC')
->limit('1');
However, I can't use an array as the second parameter, because it only tags a string; how can I pass in the value, without actually embedding it in the string?
Based on your example you need to use quoteInto (considering you're in Zend_Db_Table):
$select->joinLeft(array('ATAG' => 'ad_tags'),
'ADM.id = ATAG.ad_id AND ADM.site_id = ATAG.site_id AND ' .
$this->getAdapter()->quoteInto('ATAG.tag_id = ?',$input_vars['tag']),
array('tag_id'))
->order('ATAG.tag_id DESC')
->limit('1');
You can also do the same with:
$select->from(array('ADM' => 'adm_table'),'*')
->joinLeft(array('ATAG' => 'ad_tags'), 'ADM.id = ATAG.ad_id', 'ATAG.tag_id')
->where('ADM.site_id =ATAG.site_id')
->where('ATAG.tag_id = ?',$input_vars['tag'])
->limit(1);
If you're in Zend_Db_Table you need to set
$select->setIntegrityCheck(false);
(Note that adm_table is just an example, since you did not tell me the table name)

Changing Zend_Db_Select's output to Zend_Db_Table_Rowset

I have the following code inside a class that extends Zend_Db_Table_Abstract:
public function fetchByFriends($id) {
/*
* SELECT * FROM list
* INNER JOIN friendship ON
* list.user_id = friendship.friend_id
* WHERE friendship.user_id = ?
*/
$select = $this->select()
->from("list")
->join("friendship", "list.user_id = friendship.friend_id")
->where("friendship.user_id = ?", $id);
$select->setIntegrityCheck(false); // allows joins within a DbTable
$stmt = $select->query();
return $this->fetchAll($stmt);
}
While the query works fine the data returned is of an array. Is there some way to refactor this so that fetchAll returns it as a Zend_Db_Table_Rowset, rather than an array?
Poor research on my part. I found the answer in Zend's reference manual:
Advanced usage
Example #27 Using a lookup table to refine the results of fetchAll()
$table = new Bugs();
// retrieve with from part set, important when joining
$select = $table->select(Zend_Db_Table::SELECT_WITH_FROM_PART);
$select->setIntegrityCheck(false)
->where('bug_status = ?', 'NEW')
->join('accounts', 'accounts.account_name =
bugs.reported_by')
->where('accounts.account_name = ?', 'Bob');
$rows = $table->fetchAll($select);

Zend DB returning NULL value

I have the following query that extends from Zend_DB_Table_Abstract
$select = $this->select()
->from('expense_details',
array('SUM(expense_details_amount) AS total'))
->where('YEAR(expense_details_date) = ?', '2010')
->where('MONTH(expense_details_date) = ?', '01')
->where('expense_details_linkemail = ?', 'xxxx#gmail.com');
However it returning a NULL value despite its "equivalent" returning the desired value
SELECT SUM(expense_details_amount) AS total FROM expense_details
WHERE
YEAR(expense_details_date) = '2010'
AND MONTH(expense_details_date) = '01'
AND expense_details_linkemail = 'xxxx#gmail.com'
Is my Zend_DB_Table construct above correct?
One thing that might be a problem is the 'AS' statement within this string literal.
array('SUM(expense_details_amount) AS total'))
Try changing it to this:
array('total' => 'SUM(expense_details_amount)'))
I believe this is how Zend_Db_Select handles AS.
After searching hard for a solution I found where the problem is.
I changed
$value = $this->fetchAll($select);
$data[] = $value->total;
to
$value = $this->fetchRow($select);
$data[] = $value->total;