zf1: chained joins - zend-framework

I'm getting an error with a query, my question is: can i chain joins?
My first join is to the primary table, but my second join is to the table joined to the primary table. This is the query:
$query = $this->getDbTable()->select()
->from(array('ca' => 'contracts_allotment'),
array('id',
'contracts_rooms_id' => new Zend_Db_Expr("CONCAT(room_type_desc, '-', room_characteristics_desc)")
))
->join(array('cr' => 'contracts_rooms'),
'ca.contract_rooms_id = cr.id',
array())
->join(array('rt' => 'room_types'),
'cr.room_id = rt.id',
array('room_type_desc'))
->join(array('rc' => 'room_characteristics'),
'cr.char_id = rc.id',
array('room_characteristics_desc'))
->where('contract_id = ?', $contractId);
var_dump($this->getDbTable()->fetchAll($query));die;
I'm getting:
Select query cannot join with another table"
The error comes from Zend/Db/Table/Select::assemble()
Here you have some inside assemble():
// Check each column to ensure it only references the primary table
if ($column) {
if (!isset($from[$table]) || $from[$table]['tableName'] != $primary) {
var_dump($from[$table]['tableName'], $primary);die;
require_once 'Zend/Db/Table/Select/Exception.php';
throw new Zend_Db_Table_Select_Exception('Select query cannot join with another table');
}
}
The var_dump() prints:
string(10) "room_types" string(19) "contracts_allotment"
Any idea?

Don't forget to lock the tables when doing joins:
$query = $this->getDbTable()->select()
->setIntegrityCheck(false)
->from(array('ca' => 'contracts_allotment'),
array('id',
'contracts_rooms_id' => new Zend_Db_Expr("CONCAT(room_type_desc, '-', room_characteristics_desc)")
))
->join(array('cr' => 'contracts_rooms'),
'ca.contract_rooms_id = cr.id',
array())
->join(array('rt' => 'room_types'),
'cr.room_id = rt.id',
array('room_type_desc'))
->join(array('rc' => 'room_characteristics'),
'cr.char_id = rc.id',
array('room_characteristics_desc'))
->where('contract_id = ?', $contractId);
->setIntegrityCheck(false) should at least get you a new error.

Related

Column already exists in LeftJoin with Zend

With relationship and joins I'm trying get the latest post of each customer.
But I don't really get it to work. I get error:
Column already exists: 1060 Duplicate column name 'custID'
Based on my searching both here and Google it could have been for * but I have removed so all table columns is specified by name so I don't get why I get column already exists?
$db = $this->getDbTable();
// create sub query
$subSql = $db->select()
->setIntegrityCheck(false)
->from(array('s1' => 'sales'), array('s1.custID', 's1.saledate'))
->joinLeft(array('s2' => 'sales'), 's1.custID = s2.custID AND s1.saledate < s2.saledate', array('s2.custID', 's2.saledate'))
->where('s2.custID IS NULL')
->limit(1);
//main query
$sql = $db->select()
->setIntegrityCheck(false)
->from(array('customers' => 'customers'), array("customers.custID"))
->joinLeft(array('sale_tmp' => new Zend_Db_Expr('(' . $subSql . ')')), "customers.custID = sale_tmp.custID", array('sale_tmp.custID'));
//echo $sql->assemble();
//exit;
$resultSet = $db->fetchAll($sql);
return $resultSet;
Since two of your tables have the field custID, there is a conflict about how to populate the custID value in your joined table.
You need to provide a column-alias for one of them. The signature of the joinLeft() method is:
joinLeft($table, $condition, [$columns])
The third argument $columns can be a straight integer-indexed array of columns (as you are using) or it can be an associative array whose values are the columns, but whose keys are the column-aliases.
So perhaps try something like:
// create sub query
// add alias for the custID field
$subSql = $db->select()
->setIntegrityCheck(false)
->from(array('s1' => 'sales'), array('s1.custID', 's1.saledate'))
->joinLeft(array('s2' => 'sales'), 's1.custID = s2.custID AND s1.saledate < s2.saledate', array('sales_custID' => 's2.custID', 's2.saledate'))
->where('s2.custID IS NULL')
->limit(1);
// main query
// add alias for custID field
$sql = $db->select()
->setIntegrityCheck(false)
->from(array('customers' => 'customers'), array("customers.custID"))
->joinLeft(array('sale_tmp' => new Zend_Db_Expr('(' . $subSql . ')')), "customers.custID = sale_tmp.custID", array('temp_custID' => sale_tmp.custID'));

missing FROM-clause entry for table "Grupo" cakephp

hi i have aproblem in my code, I want generate a list of user but this have a group and need just a group of user.
the error say:
Error: SQLSTATE[42P01]: Undefined table: 7 ERROR: missing FROM-clause entry for table "Grupo"
this is my code:
public function add()
{
$this->loadModel('SoyaProveedor');
$this->loadModel('Soya');
$this->set('oleaginosas', $this->Soya->find('list', array(
'fields'=> array('id','username'),
'conditions' => array('Grupo.categoria' => 'Soya' , 'Grupo.subcategoria' => 'Productor de Oleaginosas')
)));
if ($this->request->is('post')) {
$this->request->data['SoyaProveedor']['nombre'] = strtoupper($this->request->data['SoyaProveedor']['nombre']);
$this->request->data['SoyaProveedor']['codigo'] = strtoupper($this->request->data['SoyaProveedor']['codigo']);
if ($this->SoyaProveedor->save($this->request->data)) {
$this->Session->setFlash(__('La InformaciĆ³n fue Guardada.'));
return $this->redirect(array('action' => 'index'));
}
}
}
the sql query of the cake generate it:
SQL Query: SELECT "Soya"."id" AS "Soya__id", "Soya"."username" AS
"Soya__username" FROM "public"."users" AS "Soya" WHERE
"Grupo"."categoria" = 'Soya' AND "Grupo"."subcategoria" = 'Productor
de Oleaginosas'
You need the grupos table to be joined in the query, your query in the question has no joins. There are a number of simple solutions.
Define recursive.
Recursive is a very coarse control of what joins and queries are executed, by default find('list') has a recursive value of -1.
-1 means no joins, which is why there is no join in the resultant query. Setting it to a value of 0 adds a join to the main query for all hasOne and belongsTo associations.
Be wary of using/relying on recursive as it's very easy to generate queries with joins you don't need - and/or triggering many subsequent queries for related data (if set to a value larger than 0).
However this find call:
$data = $this->Soya->find('list', array(
'fields'=> array('Soya.id','Soya.username'),
'recursive' => 0, // added
'conditions' => array(
'Grupo.categoria' => 'Soya' ,
'Grupo.subcategoria' => 'Productor de Oleaginosas'
)
));
Should result in this query (If the Soya model has a belongsTo association to Grupo):
SELECT
"Soya"."id" AS "Soya__id",
"Soya"."username" AS "Soya__username"
FROM
"public"."users" as "Soya"
LEFT JOIN
"public"."Grupos" as "Grupo" on ("Soya"."grupo_id" = "Grupo"."id")
...
Possibly more joins
...
WHERE
"Grupo"."categoria" = 'Soya'
AND
"Grupo"."subcategoria" = 'Productor de Oleaginosas'
Or Use containable
The containable behavior allows better control of what queries are executed. Given the info in the question to use it that means:
<?php
class Soya extends AppModel {
// Assumed from information in the question
public $useTable = 'users';
public $belongsTo = array('Grupo');
// added
public $actsAs = array('Containable');
}
Will permit you to do the following in your controller:
$data = $this->Soya->find('list', array(
'fields'=> array('Soya.id','Soya.username'),
'contain' => array('Grupo'), // added
'conditions' => array(
'Grupo.categoria' => 'Soya' ,
'Grupo.subcategoria' => 'Productor de Oleaginosas'
)
));
Which will generate the following query (exactly one join):
SELECT
"Soya"."id" AS "Soya__id",
"Soya"."username" AS "Soya__username"
FROM
"public"."users" as "Soya"
LEFT JOIN
"public"."Grupos" as "Grupo" on ("Soya"."grupo_id" = "Grupo"."id")
WHERE
"Grupo"."categoria" = 'Soya'
AND
"Grupo"."subcategoria" = 'Productor de Oleaginosas'
Link your models together using associations: CakePHP Associations
Alternatively you can use custom sql-statemens using join e.g.:
$db = $this->getDataSource();
$result = $db->fetchAll(
"SELECT Soya.id AS Soya__id, Soya.username AS Soya__username FROM public.users AS Soya
join Grupo on Grupo.id = Soya.groupo_id
WHERE Grupo.categoria = ? AND Grupo.subcategoria = ?",
array('Soya', 'Productor de Oleaginosas')
);
$this->set('oleaginosas', $result);

Zend Framework Query with Joins

I am trying to replicate this query using zend framework:
SELECT
activitytype.description,
activity.datecompleted
FROM
clientactivity
INNER JOIN activity
ON activity.activityID = clientactivity.activityid
INNER JOIN activitytype
ON activitytype.activitytypeid = activity.activitytypeid
WHERE
clientactivity.clientid = 100
This is what I have so far:
$select = $dbTable->select(Zend_Db_Table::SELECT_WITH_FROM_PART);
$select->setIntegrityCheck(false);
$select->where('clientactivity.clientid = ?', $clientID);
$select->join('activity', 'activity.activityid = clientactivity.activityid');
$select->join('activitytype', 'activitytype.activitytypeid = activity.activitytypeid');
$select->columns(array('activitytype.description', 'activity.datecompleted'));
I seem to be having problems with the columns option, it doens't seem to be limiting the columns and I am ending up with
clientactivity.* etc in the column list in the query.
What am I doing wrong?
Thanks,
Martin
Try instead of the $select->columns();
$select->from('activitytype.description', 'activity.datecompleted');
Reference - http://framework.zend.com/manual/en/zend.db.select.html
UPDATE:
This example makes us of a generic database handler:
$db = Zend_Db::factory('Pdo_Mysql', array(
'host' => '127.0.0.1',
'username' => 'yourusername',
'password' => 'somepassword',
'dbname' => 'yourdbname'
));
$select = $db->select(Zend_Db_Table::SELECT_WITH_FROM_PART);
$select->from('tableName','fieldName')
->join('joinTable', 'joinTable.keyId = tableName.keyId',array())
->where('tableName.userId = ?', $userId);
$resultSet = $db->fetchAll($select);
The key piece is the blank array at the end of the join statements that specifies no records to be returned from the joined table.

Zend_Db_Table fetchAll and column names

I'm testing Zen_DB and Zend_DB_Table and I'm facing a problem:
Let's say I've got two tables
table A(id, title)
table B(id, title)
If I write something like
$db = $this->getDbTable()->getAdapter();
$query = "SELECT A.*, B.* FROM A INNER JOIN B on A.id = B.id"
$stmt = $db->query($query);
$rows = $stmt->fetchAll();
each resulting row is like ['id' => value, 'title' => value]
Question: How can the fetched rows be like ['A.id' => value, 'A.title' => value', 'B.id' => value, 'B.title' => value'] ?
Important: I don't want to modify the database schema
Your question was answered by this question

How do I go around this Zend_Form_Element_Select db error?

When i use the Zend_Form_Element_Select elements with multioptions i get this error when i pass the selected value to Zend_DB_Table to insert into the db
Message: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'accounts_status ' in 'field list'
I have extracted some code snippets that i believe will go a long way into illustrating my problem.The accounts_status field DOES exist in my table
On my form construct have added the select element and options (I have left out the other elements)
$optionsstatus = array(
'active' => 'active',
'pending' => 'pending'
);
$optionsrole = array(
'guest' => 'guest',
'user' => 'user',
'writer' => 'writer',
'admin' => 'admin'
);
$status = new Zend_Form_Element_Select('accounts_status');
$status->setLabel('Status')
->setRequired(true)
->addMultiOptions($optionsstatus);
$role = new Zend_Form_Element_Select('accounts_role');
$role->setLabel('Role')
->setRequired(true)
->addMultiOptions($optionsrole);
I use the Zend_DB_table to insert the post values from my controller
public function addaccount($username, $fullname, $email,
$password,$status,$roles,$comments)
{
$data = array(
'accounts_username' => $username,
'accounts_fullname' => $fullname,
'accounts_email' => $email,
'accounts_password' => $password,
'accounts_status ' => $status,
'accounts_roles' => $roles,
'accounts_comments ' => $comments,
);
$this->insert($data);
}
In my controller i get the post values and send them to my model
$username = $form->getValue('accounts_username');
$fullname = $form->getValue('accounts_fullname');
$email = $form->getValue('accounts_email');
$password = $form->getValue('accounts_password');
$status = $form->getValue('accounts_status');
$roles = $form->getValue('accounts_roles');
$comments = $form->getValue('accounts_comments');
$accounts = new Model_DbTable_Account();
$accounts->addaccount($username, $fullname,$email,
$password,$status,$roles,$comments);
This approach works for me except when am dealing with the Zend_Form_Element_Select elements.Am just wondering if there is a specific way of dealing with this select elements when it comes to CRUD operations.
Message: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'accounts_status ' in 'field list'
Maybe I'm crazy, but looks to me like there's an extra space on that end of that 'accounts_status ' field name.