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.
Related
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'));
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);
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.
I've got a problem. I'm trying to left join two tables with Zend Framework using $select object. Unfortunatly my tables has common field 'name' and when I'm joining one with the other the results I get is that name field from table overwrites the name field from the other.
My code is something like that:
$select->joinLeft ( array ('users' => 'users' ), $this->_name . '.employee_id = users.user_id', array ('*' ) );
How I can join tables and avoid this issue?
Use table aliases as you would in any normal sql query!
With Zend_Db aliases are written like this:
$select = $db->select()
->from(array('p' => 'products'),
array('product_id', 'product_name'))
->join(array('l' => 'line_items'),
'p.product_id = l.product_id',
array() ); // empty list of columns
The non-zend query would look like this:
SELECT p.product_id, p.product_name
FROM products AS p
JOIN line_items AS l ON p.product_id = l.product_id;
I guess it's bit late but to get all fields from two tables you must alias all the fields
$select = $db->select()
->from(array('u' => 'users'),
array('u.id'=>'u.id','u.employee_id'=>'u.employee_id','u.name'=>'u.name'))
->joinLeft(array('e' => 'employees'),
'e.id = u.employee_id',
array('e.id'=>'e.id','e.name'=>'e.name') );
And your array would look like:
array(
0=>array(
'u.id'=>'1',
'u.employee_id'=>'1',
'u.name'=>'John Doe',
'e.id'=>'1',
'e.name'=>'Worker'
),
1=>array(
...
));
I'm trying to do a group by using Zend framework. Here's my code:
$table = new TableClass();
$select = $table->select();
$select->from ("table", array("date", "column1" => "sum(column1)"));
$select->group ( array ("date") );
$results = $table->fetchAll ($select);
$result = $results[0];
$date = $result->date;
$column1 = $result->column1;
TableClass extends 'Zend_Db_Table_Abstract'.
I can see the query by looking at the mysql query log. The query is well formed - column1 is named in the query and the results look correct if I run the query in mysql workbench.
I cannot access the data in 'column1' - I always get this exception:
Uncaught exception 'Zend_Db_Table_Row_Exception' with message 'Specified column "column1" is not in the row'
I can however access the date column without issue.
I tried:
accessing the columns by array index:
$result[0]
but you get an exception (can't access the columns by index).
not using a column alias:
$select->from ("table", array("date", "sum(column1)"));
$column1 = $result["sum(column1)"];
but you get an exception (no such column "sum(column1)").
throwing in a Zend_Db_Expr:
"column1" => new Zend_Db_Expr ( "sum(column1)" )
but this doesn't help.
Some other examples I have seen suggest the use of the column names without aggregate functions, ie. "column1" instead of "sum(column1)" but that doesn't seem to me to be the answer - the query doesn't have any aggregate functions in it so mysql won't know what to do with it.
Any help appreciated.
Firstly, a quick tip for working with Zend_Db_Select (and by extension Zend_Db_Table_Select), you can view the generated SQL by invoking the toString method. It is vital to verify that your code generates the correct query before working with a result set:
$select = $table->select();
$select->from ("table", array("date", "column1" => "sum(column1)"));
$select->group ( array ("date") );
$sql = (string) $select; //Retrieve SQL as a string
Or simply
die($select); //print SQL
I wrote the following test script using your example and have no problems:
class Table extends Zend_Db_Table_Abstract
{
protected $_primary = 'id';
protected $_name = 'table';
}
$db = Zend_Db::factory('Pdo_Mysql', array(
'dbname' => 'test',
'username' => 'root',
'password' => '',
'host' => 'localhost'
));
$table = new Table($db);
$select = $table->select();
$select->from ($table, array("date", "column1" => new Zend_Db_Expr("sum(column1)")));
$select->group ( array ("date") );
$sql = (string) $select;
echo $sql;
$results = $table->fetchAll ($select);
$result = $results[0];
$date = $result->date;
$column1 = $result->column1;
echo '<br>' . $date . ': ' . $column1;
Use Zend_Debug::dump($result); to inspect data inside the Zend_Db_Table_Row if necessary.
In my case the SQL generated is as follows:
SELECT `table`.`date`, sum(column1) AS `column1` FROM `table` GROUP BY `date`