Problems with SUM() and alias with CakePHP 3 - mysql

I'm trying to do a SELECT with a SUM but I have a probleme with aliases. CakePHP 3 is used here.
In my controller, I do :
$preparations->find('all',
[ 'fields' => ['SUM(Preparations.qty) as sumqty', 'order_id', 'product_id'],
'conditions' => ['order_id IN ' => $ids],
'contain' => ['Products'],
'group' => 'product_id'
]);
But the query i have with this is :
SELECT SUM(Preparations.qty) as sumqty AS SUM(`Preparations__qty`) AS `sumqty`, Preparations.order_id AS `Preparations__order_id`, Preparations.product_id AS `Preparations__product_id`
SUM() is written twice. How can I resolve this problem ?

Try this
'fields' => ['sumqty'=>'SUM(Preparations.qty)', 'order_id', 'product_id']

Related

cakephp 3 is there something like autoFields for joins to select all fields of a join?

I have a query which selects some computed field. In order to get all other fields of the main model and associated models, I can use autoFields(true). I also need to join some tables on certain conditions.
So far the query looks like this:
$functionsBuilder = $this->MainModel->find()->func();
$documents = $this->MainModel->find('all', [
'conditions' => […],
'contain' => […],
'join' => [
'table' => 'tablename',
'alias' => 'AliasName',
'type' => 'LEFT',
'foreignKey' => false,
'conditions' => […],
],
])
->autoFields(true)
->select([
'computed_field_name' => $functionsBuilder->group_concat(['OtherModel.name' => 'literal']),
]);
The fields of the joined table are not included in the result. Usually when you want to include all fields of an associated table, you do a select call with the table class as a parameter, e.g. ->select($this->MainModel->AssociatedModel).
The table used in the join might not be any (deeper) association with the main model. Even if it also is an association, the alias defined in the join might be a different one.
What I came up with so far is to load the table class for the table referenced in the join, then change its alias, and then use that in a select. Yielding:
$this->loadModel('AssociatedModel');
$this->AssociatedModel->alias('AliasName');
$functionsBuilder = $this->MainModel->find()->func();
$documents = $this->MainModel->find('all', [
'conditions' => […],
'contain' => […],
'join' => [
'table' => 'tablename',
'alias' => 'AliasName',
'type' => 'LEFT',
'foreignKey' => false,
'conditions' => […],
],
])
->autoFields(true)
->select($this->AssociatedModel)
->select([
'computed_field_name' => $functionsBuilder->group_concat(['OtherModel.name' => 'literal']),
]);
The result then contains all fields from the join with the correct AliasName.
I was just wondering whether there is a better way to do this. If I have a lot of joins I need to load a lot of table classes and alias them correctly. It is doable, but is there maybe a more elegant solution?

how to add limit in cakephp having joins

following is my code to fetch record from table
$joins=array(
array(
'table' => 'users',
'alias' => 'User',
'type' => 'LEFT',
'conditions' => array(
'User.id= Notification.UserId'
)
)
);
// fetching all records
$returnArray = $this->find('all', array(
'fields' => array('Notification.id','User.Name'),
'joins' => $joins,
'order' => 'Notification.id DESC',
'limit'=>'100',
));
In above code my limit is not working coz i am using joins. can anybody tell me how to use limit with joins in cakephp.
Is there any other method to add limit? PLease tell me ASAP
Thanks in advance
I'm not familiar with Cake, but try an integer instead of string with your limit.
$returnArray = $this->find('all', array(
'fields' => array('Notification.id','User.Name'),
'joins' => $joins,
'order' => 'Notification.id DESC',
'limit'=> 100,
));

Fetch random row from group by query (mysql) in Cakephp

I have a table 'activities' and the columns are grouped by three of its attributes. Now I want to fetch Activity ID that is randomly selected from all the set of groups. The query is as follows:
$act = $this->find('all', array('conditions' => $cond,
'limit' => $limit,
'fields' => array('count(*) as count, Activity.id as id'),
'page' => $page,
'group' => $group,
));
These are the things I tried and none of them worked.
1. Create a self join which should have random records
$this->bindModel(array(
'belongsTo' => array(
'Random' => array(
'className' => 'Activity',
'order' => 'rand()',
'foreignKey' => 'id',
'fields' => 'Random.id'
)
)
));
This failed because the rand() order is appended in the end which simply randomizes all fetched activities.
Added a join option
'joins' => array(
array(
'table' => 'activities',
'alias' => 'Random',
'type' => 'LEFT',
'conditions' => array(
'Activity.id = Random.id'
),
'fields' => 'Random.id',
'order' => 'rand()'
)
This also didn't work as order value is not parsed by Cake
Tried to add condition
'Activity.id >= floor(rand() * (max(Activity.id) - min(Activity.id)) - min(Activity.id))'
Gave a mysql error
Please help me out
Assuming that your query is working:
$act = $this->find('all', array('conditions' => $cond,
'limit' => $limit,
'fields' => array('count(*) as count, Activity.id as id'),
'page' => $page,
'group' => $group,
'order' => 'rand()',
'limit' => '1' // if you only want one random activity ID
));
Ok finally figured it out. We need to hack the way cake php works. In place of table name, I wrote a query to fetch randomly ordered records. Also notice the join type is 'right'. Left join wont produce randomly sorted list
$activities = $this->find('all', array('conditions' => $cond,
'page' => $page,
'limit' => $limit,
'fields' => array('count(*) as count, Random.id as id, max(Activity.modified) as Modified'),
'group' => $group,
'order' => 'Modified desc',
'joins' => array(
array(
'table' => '(select * from activities order by rand())',
'alias' => 'Random',
'type' => 'RIGHT',
'conditions' => array(
'Activity.id = Random.id'
),
)
)
));

ISNULL not working in order in CAKEPHP

I am using LEFT join and as a result getting null values for is_read column in Messages table. I want to keep the nulls at bottom when ordering. I'm using this in paginator. Following is the my code for doing the same:
$this->Paginator->settings = array(
'fields' => array('User.*'),
'joins' => array(
array('table' => 'messages',
'alias' => 'Message',
'type' => 'LEFT',
'conditions' => array(
'User.id = Message.user_from_id'
)
),
),
'limit' => 20,
'group' => array('User.id'),
'order' => array('ISNULL(Message.is_read)' => 'asc','Message.is_read' => 'asc', 'Message.created' => 'asc'),
);
The query Cakephp generates for this is as follows:
SELECT `User`.*, (CONCAT(`User`.`first_name`, ' ', `User`.`last_name`)) AS `User__full_name` FROM `srs_development`.`users` AS `User` LEFT JOIN `srs_development`.`messages` AS `Message` ON (`User`.`id` = `Message`.`user_from_id`) WHERE 1 = 1 GROUP BY `User`.`id` ORDER BY `Message`.`is_read` asc, `Message`.`created` asc LIMIT 20
ISNULL function is getting omitted in the final query.
Also please suggest a way to accomplish this without using custom pagination() if possible.
Aggregate functions didn't work in the order clause when using Pagination component. I tried declaring a virtual field in Message model as:
public $virtualFields = array(
'sortme' => "ISNULL(Message.is_read)",
);
So finally, declaring it as virtual field in the Message model did the job.
Thank you everyone.

SQL request does not work correctly

my problem is very simple. I have a table named 'articles' and I'd like to get the first three recent articles order DESC. But I want also these articles be displayed if their publication date is older or equal to today. So I've had an other condition in my request. My cakephp code is the following :
$this->set('lastArticles', $this->Article->find('all', array(
'conditions' => array('Article.visible' => true),
'Article.publication_date <= ' => date('Y-m-d'),
'order' => array('Article.creation_date DESC', 'Article.id DESC'),
'limit' => 3
)));
But the problem is even if the articles with a publication date > date('Y-m-d') these ones are displayed too! Does anyone have an idea ? Thanks in advance for your answer.
Looks like your publication_date condition isn't in the conditions array. Your code should look like this:
$this->set('lastArticles', $this->Article->find('all',
array(
'conditions' => array(
'Article.visible' => true,
'Article.publication_date <= ' => date('Y-m-d')
),
'order' => array(
'Article.creation_date DESC',
'Article.id DESC'
),
'limit' => 3
)));
A bit of extra indentation and whitespace is your friend here.
See this
$conditions = array(
'Article.visible' => true,
'Article.publication_date <= ' => date('Y-m-d')
);
$order = array('Article.creation_date DESC', 'Article.id DESC');
$lastArticles = $this->Article->find('all', array(
'conditions' => $conditions,
'order' => $order,
'limit' => 3
);
$this->set('lastArticles', $lastArticles);