Yii2: how to use a sum function with a find()? - sql

I have a find function in my CarsSearch model that I use in a GridView widget:
$query = Cars::find();
Now I need to add an SQL SUM function to that find funtion but it doesn't work. SO I tried to show the SQL query and I got this error:
$query = Cars::find()->sum('price');
echo $query->createCommand()->sql; // Call to a member function createCommand() on integer

Method ActiveQuery::sum() executes SQL query and already returns it's result.
You don't need to do anything else with it.
echo Cars::find()->sum('price');
This will output the sum of column price for all rows in table.
If you want to add some conditions or other things you need to do that before calling sum() method.
echo Cars::find()->where(['category' => 'SUV'])->sum('price')
This will output sum of price for all cars with "SUV" as their category.
If you need to use sql SUM() function for one column in query selecting more columns you can't use ActiveQuery::sum() method. Instead you can use select() or addSelect() method to tell the query what columns you want to select.
$query = Cars::find()
->select([
'sumPrices' => 'SUM(price)',
'countCars' => 'COUNT(*)'
]);
See the documentation for more info.

Related

Add where clause to calculated field in cakephp 3 query

I have a query in which I want the name of a company and its employee quantity. The thing is I want to filter this result by some conditions (like employee_number > 50 etc.). My problem is that, when building the query, I don't know how to filter this result, as the condition is set over a calculated field, so when applying the condition it gives me the below
Error: `SQLSTATE[42S22]: Column not found: 1054 Unknown column 'employee_number' in 'where clause'`.
I have been trying different things, but this is what I currently have:
$query = $this->Companies->find('all')->where($conditions)->contain(['Users']);
$query
->select(['Users.name',
'Company.modified',
'employee_number' => $query->func()->count('DISTINCT(Employees.id)')])
->where('employee_number >' => 50 )
->leftJoinWith('Employees', function (\Cake\ORM\Query $query) {
return $query->where(['deleted' => 0]);
})
->group(['Employees.company_id', 'Company.id']);
First things first, you cannot refer to an aggregate in the WHERE clause, as grouping happens afterwards, hence the error, the field employee_number doesn't exist when the WHERE conditions are being applied, you have to leverage the HAVING clause instead.
Depending on the DBMS that you are using you can reference the column from the select list, MySQL for example allows that:
$query
->select([
'Users.name',
'Company.modified',
'employee_number' => $query->func()->count('DISTINCT Employees.id')
])
->leftJoinWith('Employees', function (\Cake\ORM\Query $query) {
return $query->where(['deleted' => 0]);
})
->group(['Employees.company_id', 'Company.id'])
->having(['employee_number >' => 50]);
while Postgres for example doesn't, and requires you to repeat the aggregation inside of the HAVING clause:
->having(function (
\Cake\Database\Expression\QueryExpression $exp,
\Cake\ORM\Query $query
) {
return $exp->gt($query->func()->count('DISTINCT Employees.id'), 50);
});
ps. using DISTINCT should only be necessary when you have for example multiple joins that would result in duplicate joined rows.
See also
Cookbook > Database Access & ORM > Query Builder > Aggregates - Group and Having

Is there any way to set multiple LIKE options inside where clause in cakephp 3

I want to retrieve all rows matched on multiple partial prase against with a column. My situation can be explained as following raw sql:
SELECT *
FROM TABLENAME
WHERE COLUMN1 LIKE %abc%
OR COLUMN1 LIKE %bcd%
OR COLUMN1 LIKE %def%;
Here, abc, bcd, def are array elements. i.e: array('abc','bcd','def'). Is there any way to write code passing this array to form the above raw sql using cakephp 3?
N.B: I am using mysql as DBMS.
probably you can use Collection to create a proper array, but I think a foreach loop will do the job in the same amount of code. So here is my solution supposing $query stores your Query object
$a = ['abc','bcd','def'];
foreach($a as $value)
{
$or[] = function ($exp, $q) use ($value) {
return $exp->like('column1', '%'.$value.'%');
};
}
$query->where(['or' => $or]);
you could also use orWhere() but I see it will be deprecated in 3.6

How to write database/SQL query in Yii2, with and without a model

I have a table with multiple column and I want to return a column name using another column name as search criteria. How do I achieve this in yii2?
Below is sample code, normal sql should be:
$name = SELECT type_name FROM ProductTable WHERE type_id = 1;
echo $name;
This should return the value of the column type_name where the value of the column type_id equals 1. I tried this, but it doesn't work
$type_name = ProductTable::find()->where(['type_id' =>$model->type_id]);
$type_name = Product::find(['type_name'])->where(['type_id' =>$model->type_id]);
I also tried this, but I guess it was wrong
I hope my question is clear enough and any help will he appreciated
and u could also use createCommand!
$name = \Yii::$app->getDb()->createCommand("SELECT type_name FROM ProductTable WHERE type_id=:typeId", ['typeId'=>$model->type_id])->queryAll();
For a general introduction to Yii2's ActiveRecord, see the guide: http://www.yiiframework.com/doc-2.0/guide-db-active-record.html
If you want the complete row and have a model, you're just missing a one():
Product::find()->where(['type_id' =>$model->type_id])->one();
If you do have a Model defined and just want a single value, try:
Product::find()->select('type_name')->where(['type_id' =>$model->type_id])->scalar();
Which basically generates an ActiveQuery via the model, and changes it to return only the first column in the first row of matched results.
If you do NOT have a model, you could also generate a normal query without ActiveRecord usage (http://www.yiiframework.com/doc-2.0/yii-db-query.html)
$name = (new Query())->select('type_name')
->from('ProductTable')
->where(['type_id' =>$model->type_id])
->scalar();
I assume you generated ProductTable by using Gii module.
Also, if type_id column is a primary key:
$product = ProductTable::findOne($model->type_id);
if($product !== null) { $product->typeName /*... read value ...*/}
or to get all records
$products = ProductTable::findAll($model->type_id); //match all records.
for any other column use the following syntax instead:
$product = ProductTable::findOne(['type_id' => $model->type_id]);
Use following code to get type_name
$PTable=ProductTable::find()->select('type_name')->where(['type_id' =>$model->type_id])->one();
echo $PTable->type_name;

Specifying a WHERE clause after a JOIN clause - Active Record - CodeIgniter

I wanted to ask is it possible to specify a where clause after a join in order to match data to a users input. Say for example I have the following code:
$this->db->select('user.*,role.*')
$this->db->from('user');
$this->db->where('user.username', $username);
$this->db->where('user.password', $password);
$this->db->join('role','role.id = user.role_id')
$result = $this->db->get();
and I want to query the matching data from the table 'role':
$this->db->select('user.*,role.*')
$this->db->from('user');
$this->db->where('user.username', $username);
$this->db->where('user.password', $password);
$this->db->join('role','role.id = user.role_id')
$this->db->where('role.speaker', $speaker); //want to know if this is correct
$result = $this->db->get();
Is this possible? Can I compare results (using WHERE) after a JOIN? Will that produce results matching to the WHERE clause?
Thanks!
CodeIgniter doesn't actually build the query until ->get() is called. You can call the methods in whatever order you want.

Yii Framework: How to get the num_rows?

As the official documentation does not say how to do a simply "num_rows" with their system, i need some help here: How to get the amount of rows in the result set ?
Assuming:
$connection=Yii::app()->db;
$command=$connection->createCommand($sql);
This will work for insert, update and delete:
$rowCount=$command->execute();
execute(): performs a non-query SQL statement, such as INSERT, UPDATE and DELETE. If successful, it returns the number of rows that are affected by the execution.
For select, you could do the following:
$dataReader=$command->query();
This generates the CDbDataReader instance and CDbDataReader provides a rowCount property
http://www.yiiframework.com/doc/api/1.1/CDbDataReader#rowCount-detail
$rowCount = $dataReader->rowCount;
About rowCount => Returns the number of rows in the result set. Note, most DBMS may not give a meaningful count. In this case, use "SELECT COUNT(*) FROM tableName" to obtain the number of rows.
ActiveRecord has count method which can be used.
$cntCriteria = new CDbCriteria();
$cntCriteria->condition = "categoryId = :categoryId";
$cntCriteria->params[':categoryId'] = $categoryRow->categoryId;
$articleCount = Article::model()->count($cntCriteria);
There is one more way to do this. When we execute a sql query it will return the result as array only. So we can able get the count of the rows using count() function like below.
$output=User::model()->findAllBySql("select * from user");//User is a model belongs to the user table
$count_val=count($output);//$count_val has the value of number of rows in the output.