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;
Related
I know its a common question but I get a specific error about a not joined table.
My main Model (Group) has this relation (1:1):
return array(
'groupType'=>array(self::BELONGS_TO, 'GroupType', 'groupTypeId','order'=>'name ASC');
As you can see, I've tried to put an order attributes thats is not working.
As you can immagine, my other module, GroupType, has an attribute called 'name'.
In the grid view, the relation model is printed well simply using the name of relation:
array(
'name'=>'groupType',
'value'=>'$data->groupType->name'
),
Autoload is working fine in GridView.
Unfortunally the column is not sortable. So I put a CSort parameter to DataProvider provided in the Search Method as below:
$sort = new CSort();
$sort->defaultOrder = 'id asc';
$sort->attributes = array(
'groupType'=>array(
'asc'=>'groupType.name asc',
'desc'=>'groupType.name desc'
),
'description'=>array(
'asc'=>'t.description asc',
'desc'=>'t.description desc'
),
'name'=>array(
'asc'=>'t.name asc',
'desc'=>'t.name desc'
),
'*');
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
'sort'=>$sort
));
Ordering by description and name (attribute of Group) works fine. When I tried to order by groupType, i get this simply error:
SQL: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'groupType.id' in 'order clause'. The SQL statement executed was: SELECT * FROM `cprol_groups` `t` ORDER BY groupType.idname asc LIMIT 20
As you can see, framework is not joining my related table. And in this case, what Alias I have to use due to same-property name?
Thanks you for any advice!
I've resolved forcing the join.
In the criteria, I have to force join:
$criteria->join = 'join '.GroupType::model()->tableName().' gt on gt.id = t.groupTypeId';
or using the ->with statement:
$criteria->with = 'groupType';
removing the default order in relation and adding an alias:
return array('groupType'=>array(self::BELONGS_TO, 'GroupType', 'groupTypeId','alias'=>'gt'));
so you can order by relation field:
$sort = new CSort();
$sort->defaultOrder = 'gt.name asc';
$sort->attributes = array(
'groupTypeId'=>array(
'asc'=>'gt.name asc',
'desc'=>'gt.name desc'
),
I'm relatively new to Yii.
I fell confident with raw SQL but still get a bit lost when it comes to
ORM. So this may be a dummy question.
I've retrieved all necessary records building such CDbCriteria:
$criteria = new CDbCriteria(array(
'select' => 'sum(items) as items',
// 'condition' => 't.items > 0 and order.storage = "'Product::STORAGE_LOCAL . '"',
'condition' => 't.items > 0 and order.storage = "' . Product::STORAGE_LOCAL . '"',
'order' => 'sum(items) DESC',
'with' => array(
'product' => array(
'select' => 'code, title, producer, local_rest',
**// 'select' => 'code, title, producer, sum(local_rest) as local_rest',**
'group' => 'product.code',
)
),
'join' => 'inner join `order` `order` on `t`.`order_id` = `order`.`id`',
// 'group' => '`product`.`code`, `product`.`title`',
'group' => '`product`.`code`',
'together' => true
));
I try to get sum of local_rest field doing group by. Unfortunately it does not return what it should be.
This is how I tried to build in it into CDbCriteria:
// 'select' => 'code, title, producer, sum(local_rest) as local_rest',.
- no luck.
I can get the it using separated query as:
$sum_local_rest = Yii::app()->db->createCommand("
SELECT id,code, title, sum(local_rest) as sum_rest FROM product GROUP BY code
ORDER BY `sum_rest` DESC
");
One more caution - there are duplicate records in product table.
I.e. we have the same product more than one time. But if I use GROUP BY it helps to delimiter this shortcoming. This is due to bad DB design and should be fixed in the future.
The problem is that I need somehow to bind it with CDbCriteria, because it's used by CDataProvider and CDataProvider is used by GridView.
Any tips how to connect these two question in one CDbCriteria?
Thanks in advance
EDIT
Looking at the current answers I feel I need summarize. The main problem is that I need to tell CDbCriteria to retrieve records (bound by HAS_Many connections) and to calculate SUM of all these records and to make CDbCriteria to do GROUP BY of these records.
No other way. I can't do it explicitly. Because I pass CDbCriteria to CDataProvider and it should run queries. This is how things work in Yii (as far as I understand).
//You can merge your criteria like here:
$criteria = new CDbCriteria(); //First criteria
$criteria_2 = new CDbCriteria(); //Second criteria
$criteria->mergeWith($criteria_2); //Merge criteria and criteria_2
SomeModel::model()->findAll($criteria); //Find by criteria
I don't see why something like this shouldn't work:
$criteria = new CDbCriteria;
$criteria->select = array(
"SUM(t.items) as items",
"SUM(product.local_rest) as product_local_rest"
);
$criteria->condition = "t.items > 0 and order.storage = "' . Product::STORAGE_LOCAL . '"';
$criteria->join = 'inner join `order` `order` on `t`.`order_id` = `order`.`id`';
$criteria->with = "product";
$criteria->group = "product.code";
$criteria->together = true;
Since you're setting together to true, the columns of your relation should be available to your query, aliased by the relation's name (product). (Note: to access the result of SUM(product.local_rest) on the models returned by CActiveDataProvider, you'll need to set $product_local_rest as a public property on the class of the returned models.)
Alternatively, if you're more comfortable writing raw SQL, you could use CDbCommand to generate an array of results, and then use CArrayDataProvider instead of CActiveDataProvider. http://www.yiiframework.com/doc/api/1.1/CArrayDataProvider
You also don't have to pass all elements to criteria. Try to split criteria into more code like this:
$criteria = new CDbCriteria();
$criteria->select = 'sum(items) as items, ' . Product::STORAGE_LOCAL;
$criteria->condition = 't.items > 0 and order.storage = ' . Product::STORAGE_LOCAL;
//etc.
I want to make my CGridView columns searchable after reading this the problem is when i use one cdbCriteria->with condition it works fine. But It gives an error when i add more than one cdbCriteria->with condition. More specifically I am pasting my code here.
$criteria=new CDbCriteria;
$criteria->with = array( 'teacherGradeSection','course' );
$criteria->with = array( 'teacherGradeSection','teacher' );
$criteria->together = true;
$criteria->compare('course.name', $this->course_search, true );
$criteria->compare('teacher.firstname', $this->teacher_search, true );
When i use only one with condition it works fine but gives an error when more than one with condition is used.
Error
SQLSTATE[42S22]: Column not found: 1054 Unknown column
Edit 1:
These are the available relations
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(
'submissions' => array(self::HAS_MANY, 'Submission', 'task_id'),
'teacherGradeSection' => array(self::BELONGS_TO, 'TeacherGradeSection', 'teacher_grade_section_id'),
'course' => array(self::HAS_MANY, 'Course', array('course_id'=>'id'),'through'=>'teacherGradeSection'),
'teacher'=> array(self::HAS_MANY,'Teacher',array('teacher_teacher_id'=>'teacher_id'),'through'=>'teacherGradeSection'),
); }
As suugested by #Nisic and #Noam148 when i use $criteria->with=array('teacherGradeSection','course','teacher ')
I got the following error
CDbCommand failed to execute the SQL statement: SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 'teacherGradeSection'. The SQL statement executed was: SELECT COUNT(DISTINCT `t`.`id`) FROM `task` `t` LEFT OUTER JOIN `teacher_grade_section` `teacherGradeSection` ON (`t`.`teacher_grade_section_id`=`teacherGradeSection`.`id`) LEFT OUTER JOIN `course` `course` ON (`course`.`id`=`teacherGradeSection`.`course_id`) LEFT OUTER JOIN `teacher_grade_section` `teacherGradeSection` ON (`t`.`teacher_grade_section_id`=`teacherGradeSection`.`id`) LEFT OUTER JOIN `teacher` `teacher` ON (`teacher`.`teacher_id`=`teacherGradeSection`.`teacher_teacher_id`)
try defining two relations that will resolve the conflict
'teacherGradeSection' => array(self::BELONGS_TO, 'TeacherGradeSection', 'teacher_grade_section_id'),
'teacherGradeSectiontwo' => array(self::BELONGS_TO, 'TeacherGradeSection', 'teacher_grade_section_id'),
and in your criteria
$criteria->with['course'] = array( 'teacherGradeSection','course' );
$criteria->with['teacher']= array( 'teacherGradeSectiontwo','teacher' );
Your second with will actually replace your first with so you will not eager load the course, so when you later reference it in compare you get the error.
You need only one with that prepares both, course and teacher. I can't be sure how to write it without the database schema, but you can blind try this:
$criteria->with = array( 'teacherGradeSection','course', 'teacher' );
or just explain us the relations
You can use the $criteria->with property one time. When you used $criteria->with for the second time you override the first one.
See here how to use the with property. On this way you add 3 different relations to your 'CDbCriteria':
$criteria=new CDbCriteria;
$criteria->with = array( 'teacherGradeSection','course','teacher');
$criteria->together = true;
$criteria->compare('course.name', $this->course_search, true );
$criteria->compare('teacher.firstname', $this->teacher_search, true );
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
I am trying to do a Join query using CDBCriteria in Yii framework. The issue is the join query works successfully but it does not display the columns from other tables.
I am doing in the following way
$criteria = new CDbCriteria;
$criteria->order = 't.id desc';
$criteria->select = '*';
$criteria->join = ' INNER JOIN table2 INNER JOIN table3 INNER JOIN table4';
When i run this, I can see only the mail table1 columns displayed. Other columns are not shown.
In my model class, I have the relation has
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(
'user' => array(self::BELONGS_TO, 'DmPhoneUser', 'user_id'),
'command' => array(self::BELONGS_TO, 'DmOtaCommand', 'command_id'),
'partner' => array(self::BELONGS_TO, 'DmPartner', 'partner_id'),
);
}
********************************************************
public function actionGetHistory($start, $per_page)
{
$partner_id = '10';
$criteria = new CDbCriteria;
$criteria->order = 't.history_id desc';
$criteria->select = 't.*, table2.*';
$criteria->join = ' INNER JOIN table2 ON t.command_id = table2.command_id';
$result = Table_1_class::model()->with('command')->findAll();
$history_data = CJSON::encode($result);
echo $history_data;
}
here command_id is common in table1 and table2.
This is how I am using the criteria code.
As I said, Yii's Active Record implementation will only use columns which are defined in the table itself or the tables you are linking to through with, not arbitrary columns you return in the resultset.
Solution 1: Define a relation to table2, add that relation to with, and get rid of join. Then you'll probably need to convert each returned object to an array - CJSON::encode will not handle a model with relations well.
Solution 2: Use Yii::app()->db->createCommand("SQL query")->queryAll(); instead of Active Record. This will produce an array of arrays, which CJSON::encode will have no problem with.