I have 3 tables:
bank
bank_details
bank_bank_details
Relation between them:
bank model:
public function relations() {
return array(
'bankBankDetails' => array(self::HAS_MANY, 'BankBankDetails', 'bank_id'),
);
}
bank_details model:
public function relations() {
return array(
'bankBankDetails' => array(self::HAS_MANY, 'BankBankDetails', 'bank_details_id'),
);
}
bank_bank_details model:
public function relations()
{
return array(
'bank' => array(self::BELONGS_TO, 'Bank', 'bank_id'),
'bankDetails' => array(self::BELONGS_TO, 'BankDetails', 'bank_details_id'),
);
}
I want to fetch bank details like bank_name, ifsc etc info in admin view of bank_details model.
The normal SQL query I have generated which works perfectly fine:
SELECT b.name
FROM bank b
LEFT JOIN bank_bank_details bbd ON bbd.bank_id = b.bank_id
LEFT JOIN bank_details bd ON bd.bank_details_id = bbd.bank_details_id
WHERE bd.bank_details_id = bbd.bank_details_id
LIMIT 0 , 30
Now I just wants to integrate this with Yii CDBCriteria but its not working for me. Please check the code below:
public function search() {
$criteria = new CDbCriteria;
// select b.name
// from bank b
// left join bank_bank_details bbd
// on bbd.bank_id = b.bank_id
// left join bank_details bd on bd.bank_details_id = bbd.bank_details_id
// WHERE bd.bank_details_id = bbd . bank_details_id;
$criteria->compare('bank_details_id', $this->bank_details_id);
$criteria->compare('first_holder_name', $this->first_holder_name, true);
$criteria->compare('nominee1', $this->nominee1, true);
$criteria->select = 'b.name';
$criteria->join = 'LEFT JOIN bank_bank_details bbd ON bbd.bank_id = b.bank_id ';
$criteria->join .= 'LEFT JOIN bank_details bd ON bd.bank_details_id = bbd.bank_details_id';
$criteria->condition = 'bd.bank_details_id = bbd.bank_details_id';
return new CActiveDataProvider($this, array(
'criteria' => $criteria,
'pagination' => array(
'pageSize' => 10,
),
));
}
Error:
Error 500 Found
CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'b.bank_id' in 'on clause'
Any help would be appreciated.
You need to set alias to your table like this:
$criteria->alias='b'; or use default alias "t" instead of "b"
read more at
http://www.yiiframework.com/doc/api/1.1/CDbCriteria#alias-detail
Try:
public function search() {
$criteria = new CDbCriteria;
$criteria->compare('bank_details_id', $this->bank_details_id);
$criteria->compare('first_holder_name', $this->first_holder_name, true);
$criteria->compare('nominee1', $this->nominee1, true);
$criteria->select = 'bank.name';
$criteria->with = array(
'bankBankDetails' => array('joinType'=>'LEFT JOIN'),
'bankBankDetails.bank' => array('joinType'=>'LEFT JOIN'),
);
$criteria->addCondition('t.bank_details_id = bankBankDetails.bank_details_id');
return new CActiveDataProvider($this, array(
'criteria' => $criteria,
'pagination' => array(
'pageSize' => 10,
),
));
}
Main table (which is in FROM) has alias t and after compare you already having some condition, than you need to add to existing, not rewrite
UPDATE
If you do query from model bank_details then the main table (in FROM) must be bank_details. Query will be:
SELECT b.name
FROM bank_details bd
LEFT JOIN bank_bank_details bbd ON bd.bank_details_id = bbd.bank_details_id
LEFT JOIN bank b bbd ON bbd.bank_id = b.bank_id
WHERE bd.bank_details_id = bbd.bank_details_id
LIMIT 0 , 30
here
$criteria->select = 'b.name';
You are selecting only bank name and no id is selected
Not sure with the yii format something like
$criteria->select = 'b.name,b.bank_id';
or
$criteria->select = array('b.name,b.bank_id');
As #Evgeniy mentioned, you will need to set the alias using $criteria->alias = 'b';
http://www.yiiframework.com/doc/api/1.1/CDbCriteria#alias-detail
You might also want to look into using CDbCriteria::with you can use this to select related models.
http://www.yiiframework.com/doc/api/1.1/CDbCriteria#with-detail
If you use the above, make sure you also use CDbCriteria::together correctly. To select all related models at once, set it to true;
http://www.yiiframework.com/doc/api/1.1/CDbCriteria#together-detail
Related
I have a problem to relate tables in JOIN with CDbCriteria. I got it to work with a single JOIN between two tables that are related but I have the following case:
structure of tables with fields to relate:
table Tbl_recibo table tbl_domicilio table tbl_entidad
Idrecibo Iddomicilio Identidad
nombre nombre nombre
Iddomicilio Identidad
Codigo SQL:
SELECT
`rec`.`idrecibo` AS 'Num_Recibo',
`dom`.`matricula`,
`dom`.`federado`,
`ent`.`nombre` AS 'profesional',
`dom`.`calle` AS 'domicilio'
FROM
`tbl_recibo` AS rec
LEFT JOIN `tbl_domicilio` AS dom ON `rec`.`iddomicilioapertura` = `dom`.`iddomicilio`
LEFT JOIN `tbl_entidad` AS ent ON `dom`.`identidad` = `ent`.`identidad`
Codigo yii:
public function traerRecibos() {
$r = new CDbCriteria();
$dx = TblDomicilio::model()->tableName();
$ex = TblEntidad::model()->tableName();
$r->select='t.idRecibo,DX.idDomicilio';
$r->join = 'left join ' . $dx . ' DX on DX.idDomicilio = t.idDomicilio';
$r->join = 'left join ' . $ex . ' EX on EX.idEntidad=DX.idEntidad';
return new CActiveDataProvider($this, array(
'criteria' => $r,
'pagination' => array('pageSize' => Yii::app()->user->getState('pageSize', Yii::app()->params['defaultPageSize']),
)));
}
Relaciones de table tblRecibo:
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'tblEstadoreciboHasTblRecibos' => array(self::HAS_MANY, 'TblEstadoreciboHasTblRecibo', 'idRecibo'),
'tblItemrecibowebs' => array(self::HAS_MANY, 'TblItemreciboweb', 'idRecibo'),
'idCalendario0' => array(self::BELONGS_TO, 'TblCalendario', 'idCalendario'),
'idDomicilioApertura0' => array(self::BELONGS_TO, 'TblDomicilio', 'idDomicilioApertura'),
'idDomicilio0' => array(self::BELONGS_TO, 'TblDomicilio', 'idDomicilio'),
'idPaquete0' => array(self::BELONGS_TO, 'TblPaquete', 'idPaquete'),
);
}
I need to visualize the same SQL data but with CDbCriteria, I can not access the data from the tblEntidad table from tblRecibo.
You need to combine JOIN clause in this way:
$r->join = 'left join ' . $dx . ' DX on DX.idDomicilio = t.idDomicilio ';
. 'left join ' . $ex . ' EX on EX.idEntidad=DX.idEntidad';
In your code you just overwriting first assignment to $r->join.
You may also consider using with(), so you could reuse relations definitions to build JOIN conditions. See this guide article about relations.
$criteria->select = 't.*,count(business_unit.id) as TotalBusinessUnits,count(users.id) as TotalUsers ,count(positions.id) as TotalPositions, count(skills.id) as TotalSkills , users.first_name , users.last_name, count(question_bank.id) as TotalQuestions';
$criteria->condition = "`t`.status = '1'";
$criteria->group = 't.id';
$criteria->order = 'created DESC';
$criteria->join = " inner join users on users.company_id = `t`.id";
$criteria->join .= " left join business_unit on business_unit.company_id = `t`.id";
$criteria->join .= " left join billingdetails on billingdetails.company_id = `t`.id";
$criteria->join .= " left join positions on positions.company_id = `t`.id";
$criteria->join .= " left join skills on skills.company_id = `t`.id";
$criteria->join .= " left join question_bank on question_bank.company_id = `t`.id";
It works fine and get all columns which I select.
But when I pass it in CActiveDataProvider it gets only this attributes.
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
'pagination' => $pages
));
How I select all columns?
In Yii if you are using as for sql, it needs a public variable to store the value in.
add all your custom column names as public variables on the model and all should be dandy.
so if you have $criteria->select = 't.*,count(business_unit.id) as TotalBusinessUnits, this will create the corresponding sql . but Yii does not recognise TotalBusinessUnits as a valid column on the table.
So if you add public $TotalBusinessUnits; in your model Yii has a place to store this value.
Also you should then add TotalBusinessUnits to your safe attributes rule so that Yii knows it safe to fetch.
public $TotalBusinessUnits;
public function rules(){
return array(
// your rules
array('TotalBusinessUnits','safe'),
);
}
public function search(){
$criteria->select = 't.*,count(business_unit.id) as TotalBusinessUnits';
// your criteria
return new CActiveDataProvider($this, array(
'criteria' => $criteria,
));
}
Is it possible to write sub queries with Yii active record?
I need to add a subquery in the FROM clause. Below is the SQL with the subquery but I want to specifically write it using Active Record.
In SQL, Policy has a many to many relationship with policy_vehicles.
SQL Query:
select * from (SELECT Name , GROUP_CONCAT(PV.VehicleId SEPARATOR ',') as VehicleIds
FROM `policies` `t`
LEFT JOIN policy_vehicles PV USING(PolicyId)
WHERE (Type IN ('C', 'E')) AND (Status='Active')
GROUP BY t.PolicyId
) k where VehicleIds like '%1%' AND VehicleIds like '%2%'
This is how I want to use it in the Controller class:
$model = Policy::model();
$model->Status = array('Active');
$model->VehicleIds = array(1,2);
$model->Type = array('C', 'E');
$datas = $model->search()->getData();
print_r($datas);
Search function in the model:
public function search() {
$joins = array();
$criteria = new CDbCriteria;
$criteria->compare('Type', $this->Type);
$criteria->compare('Status', $this->Status);
array_push($joins, 'LEFT JOIN policy_vehicles PV USING(PolicyId)');
$criteria->join = implode(' ', $joins);
return new CActiveDataProvider($this, array(
'criteria' => $criteria,
));
}
So, I'm trying to do a query to get the last entries of each user using CakePHP relationship. In my Map and User model I have:
class Map (and User) extends AppModel {
public $hasMany = 'Geolog';
}
And I'm trying to doing this query to catch the last entry of each user. dg_maps and dg_users have a many to many relation.
SELECT
dg_users.id,
dg_users.email,
dg_maps.id,
dg_maps.latitude,
dg_maps.longitude,
dg_maps.timestamp
FROM
(SELECT
*
FROM
dg_maps
ORDER BY dg_maps.timestamp DESC) dg_maps
JOIN
dg_geologs ON dg_geologs.map_id = dg_maps.id
JOIN
dg_users ON dg_users.id = dg_geologs.user_id
GROUP BY dg_geologs.user_id;
What I'm doing now is:
$this->Map->query('SELECT dg_users.id, dg_users.email, dg_maps.id, dg_maps.latitude, dg_maps.longitude, dg_maps.timestamp FROM (SELECT * FROM dg_maps ORDER BY dg_maps.timestamp DESC) dg_maps JOIN dg_geologs ON dg_geologs.map_id = dg_maps.id JOIN dg_users ON dg_users.id = dg_geologs.user_id GROUP BY dg_geologs.user_id');
But, I know that a better method then this, using Cake methods. So, how can I do this?
Thank you all!
I used this for my project it is very simple
Easy way to generate CakePHP HABTM joins for use in pagination.
So put this in your model (note for function arguments - there is error in function from link )
public function generateHabtmJoin ($joinModel, $joinType = 'INNER') {
// If the relation does not exist, return an empty array.
if (!isset($this->hasAndBelongsToMany[$joinModel])) {
return array();
}
// Init joins, and get HABTM relation.
$joins = array();
$assoc = $this->hasAndBelongsToMany[$joinModel];
// Add the join table.
$bind = "{$assoc['with']}.{$assoc['foreignKey']} = {$this->alias}.{$this->primaryKey}";
$joins[] = array(
'table' => $assoc['joinTable'],
'alias' => $assoc['with'],
'type' => $joinType,
'foreignKey' => false,
'conditions' => array($bind),
);
// Add the next table.
$bind = "{$joinModel}.{$this->{$joinModel}->primaryKey} = {$assoc['with']}.{$assoc['associationForeignKey']}";
$joins[] = array(
'table' => $this->{$joinModel}->table,
'alias' => $joinModel,
'type' => $joinType,
'foreignKey' => false,
'conditions' => array($bind),
);
return $joins;
}
and you can call this function from your controller
You have example in link
i'm having some problems using a custom made function to search specific data from my database.
I have TableA(id,....) and TableB(id, tablea_id, userid,...)
Model TableA has the following relation code:
'relation_name' => array(self::HAS_MANY, 'TableB', 'tablea_id')
I need to create a custom made function to query TableA and give me results that exist on TableA that contain a certain userid on TableB data, also TableB is related to TableA from tablea_id field.
I found the solution for my problem by using this code:
public function findABCD($user_id)
{
$criteria=new CDbCriteria;
$criteria->join = 'left join TableB on t.id=TableB.tablea_id';
$criteria->condition = "TableB.userid = ".$user_id;
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
This works, but I'm not taking advantage of the relation that I have created earlier.
Any ideas of what I need to use?
I tested a lot of things but I'm receiving an SQL error.
This is what I have tested earlier (instead of the criteria Join and the Condition):
$criteria->with=array('relation_name');
$criteria->condition = "relation_name.userid= ".$user_id;
//this does not work as well
//$criteria->condition = "TableB.userid= ".$user_id;
The error is this:
SQL: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'relation_name.userid' in 'where clause'.
Any ideas?
I do this kind of joins with ActiveRecord queries, not sure if it will work for CActiveDataProvider:
$criteria->with = array(
'relation_name' => array(
'joinType' => 'INNER JOIN',
'on' => 'user_id = :user_id',
'params' => array( 'user_id' => $userId )
)
);
$criteria->together = true;