Subquery With Yii Active Record - php

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,
));
}

Related

How to write sql query in yii2

I have a raw sql query which i run using yii2 Yii::$app->db->createCommand() but then i wonder i how i can use yii's method of writing queries to actualize the same thing.
$m = "SELECT p.basic_plan_amt AS basic,p.premium_plan_amt AS premium,p.daju_plan_amt AS daju,c.name
AS country FROM price p LEFT JOIN country c ON p.country_id = c.id WHERE p.country_id = " .$country_id;
though the above query works well and provide expected result, but then how can i write the same query using the below format
$model = \backend\models\Price::find()->select([p.basic_plan_amt AS basic,p.premium_plan_amt AS
premium,p.daju_plan_amt AS daju,c.name
AS country])->where(['country_id' => $country_id])->all();
Below are the examples of query in yii hope it will help you More reference
Relation Model
$model = User::find()
->with('comments')
->all();
foreach ($model as $user) {
// get data from relation model
$comments = $user->comments;
......
foreach($comments as $comment){
........
}
}
joinWith()
Sample 1:
$model = User::find()
->joinWith('comments')
->all();
Sample 2:
$model = User::find()
->joinWith('comments')
->orderBy('tbl_comments_id.id, tbl_user.id')
->all();
innerJoinWith()
$model = User::find()
->innerJoinWith('comments', false)
->all();
// equivalent to the above
$model = User::find()
->joinWith('comments', false, 'INNER JOIN')
->all();
Join()
JOIN_TYPE = INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN etc
Syntax
$query = new Query;
$query ->select(['SELECT COLUMNS'])
->from('TABLE_NAME_1')
->join( 'JOIN_TYPE',
'TABLE_NAME_2',
'TABLE_NAME_2.COLUMN =TABLE_NAME_1.COLUMN'
);
$command = $query->createCommand();
$data = $command->queryAll();
Sample 1:
$query = new Query;
$query ->select([
'tbl_user.username AS name',
'tbl_category.categoryname as Category',
'tbl_document.documentname']
)
->from('tbl_user')
->join('LEFT OUTER JOIN', 'tbl_category',
'tbl_category.createdby =tbl_user.userid')
->join('LEFT OUTER JOIN', 'tbl_document',
'tbl_category.cid =tbl_document.did')
->LIMIT(5) ;
$command = $query->createCommand();
$data = $command->queryAll();
Output Query
SELECT `tbl_user`.`username` AS `name`, `tbl_category`.`categoryname` AS `Category`
FROM `tbl_user`
LEFT OUTER JOIN `tbl_category` ON tbl_category.createdby =tbl_user.userid
LEFT OUTER JOIN `tbl_document` ON tbl_category.cid =tbl_document.did
LIMIT 5
leftJoin()
Sample 1:
$query = new Query;
$query ->select(['tbl_user.username AS name', 'tbl_category.type as Category'])
->from('tbl_user')
->leftJoin('tbl_category', 'tbl_category.createdby = tbl_user.userid')
->limit(2);
$command = $query->createCommand();
$data = $command->queryAll();
Output Query
SELECT `tbl_user`.`username` AS `name`, `tbl_category`.`type` AS `Category`
FROM `tbl_user`
LEFT JOIN `tbl_category` ON tbl_category.createdby = tbl_user.useridd
LIMIT 2
use createcommand() method:
use yii\db\Query();
$connection = \Yii::$app->db;
$query = new Query;
$insql = $connection->createCommand("SELECT* FROM inventory );
$result=$insql->queryAll();
the above method list all data from the inventory table.

CActiveDataProvider doesnt give selected columns

$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,
));
}

Zend Framework 2: how to get columns from joined tables?

I am using Zend Framework 2.4 with TableGateway and need to execute the following query:
SELECT products.title, student.firstname, orders.order_id,
orders.profile_id, orders.status
FROM student
INNER JOIN
(products
INNER JOIN orders ON products.product_id = orders.product_id)
ON student.student_id = orders.student_id
WHERE (((orders.profile_id)='.$id.'));
Here is what I am using:
$select = $this->tableGateway->getSql()->select();
$select->columns(array('*'))
->join('products', 'products.product_id = orders.product_id', array('title'))
->join('student', 'student.student_id = orders.student_id', array('first_name'))
->where(array('orders.profile_id' => $id));
$items = $this->tableGateway->selectWith($select);
return $items;
The problem is that $items does not contain the columns title or first_name. It only contains the columns from the orders table.
What do I need to do to get $items to contain the columns from the joined tables?
try to use an associative array
$select = $this->tableGateway->getSql()->select();
$select->columns(array('*'))
->join('products', 'products.product_id = orders.product_id', array('title' => 'product_title'))
->join('student', 'student.student_id = orders.student_id', array('first_name' => 'student_first_name'))
->where(array('orders.profile_id' => $id));
$items = $this->tableGateway->selectWith($select);
return $items;

Yii CDBCriteria Complex Join Query

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

Doing Join query using CDBCriteria

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.

Categories