Cakephp 3.5 InnerJoin - mysql

I have following situation.
i have a table "drivers_events" in this there are stored the drivers which are booked for an event.
Now I would like to do following
SELECT
Driver.id,
Driver.name
FROM
drivers AS Driver
INNER JOIN
drivers_events AS Listing
ON Driver.id = Listing.driver_id
WHERE
Listing.event_id = 83
ORDER BY
Driver.name ASC;
If I run it as a SQL query in phpmyadmin, it works perfectly and I get the correct id and name from the table "drivers".
When I do this in my controller like this
$drivers = $this->Jobs->query("
SELECT
Driver.id,
Driver.name
FROM
drivers AS Driver
INNER JOIN
drivers_events AS Event
ON Driver.id = Event.driver_id
WHERE
Event.event_id = $activeevent
ORDER BY
Driver.name ASC
");
then i get the complete array of jobs which created in the past.
What did i do wrong ?
It would be great if someone could help me.
Thanks in advance

I tried a lot more. I have come to the conclusion that I can read out the drivers who are assigned to an event.
in the controller it looks like this
$drivers = $this->Jobs->drivers_events->find('list',
[
'conditions' =>
[
'drivers_events.event_id' => $this->request->session()->read('Event.active')
],
'keyField' => 'driver_id',
'valueField' => 'driver_id'
]
);
In the model
$this->belongsTo('drivers_events', [
'foreignKey' => 'event_id',
]);
So now I get the right drivers for a driving job within an event.
But how do I get the name of the driver from the "Drivers" table instead the ID ?
Thx for help

Event key word is reserved for SQL.
Please do not use it for table alias.
Or use such this method.
drivers_events AS `Event`
Hope to be useful.
$result = $this->Jobs->find()
->enableAutoFields(true)
->enableHydration(false)
->select([
'id' => 'Driver.id',
'Title' => "Driver.name"
])
->join([
'Events' => [
'table' => 'drivers_events',
'type' => 'INNER',
'conditions' => [
'Jobs.event_id = Events.id',
],
]
])
->join([
'Driver' => [
'table' => 'drivers',
'type' => 'INNER',
'conditions' => [
'Events.driver_id = Driver.id',
],
]
])
->where([
'Events.id' => $activeevent
])
->group('Driver.id')
->toArray();
Ref: Cakephp 3 Adding Joins

Select Drivers.id, drivers.accountname
FROM TABLE__
Join table__
Join table__
And (Brand) Totaljobs.com
Having Count <4
group By Driver.id, Drivers.Accountname
Order by (Drivers.accountname)

Related

cakephp 3.x Sub select to get a count value

after some research I created this find statement, but it doesn't work as expected:
public $virtualFields = array(
'count' => "SELECT COUNT(plans_trainings.id) FROM plans_trainings, trainings, projects WHERE plans_trainings.training_id = trainings.id AND projects.location_id = locations.id AND plans_trainings.project_id = projects.id"
);
public function trainingsPerLocationChartData(){
$this->loadModel('Locations');
$locationsDiagramData = $this->Locations->find('all', array(
'fields' => array(
'locations.id',
'locations.description',
'locations.count' /* virtuel field */
)
));
The statement will look like this:
'sql' => 'SELECT locations.id AS `locations__id`, locations.description AS `locations__description`, locations.count AS `locations__count` FROM locations Locations'
The virtual field is not recognized at all.
What do I do wrong?
UPDATE:
I found out that I have to call it like this:
'count' => "(SELECT COUNT(plans_trainings.id) FROM plans_trainings, trainings, projects WHERE plans_trainings.training_id = trainings.id AND projects.location_id = locations.id AND plans_trainings.project_id = projects.id) AS `counter`"
I added () around the select.
$locationsDiagramData = $this->Locations->find('all')
->select(['locations.id', 'locations.description', $this->virtualFields['count']]);
But I still get a wrong sql syntax:
SELECT locations.id AS `locations__id`, locations.description AS `locations__description`, (SELECT COUNT(plans_trainings.id) FROM plans_trainings, trainings, projects WHERE plans_trainings.training_id = trainings.id AND projects.location_id = locations.id AND plans_trainings.project_id = projects.id) AS `counter` AS (SELECT COUNT(plans_trainings__id) FROM plans_trainings, trainings, projects WHERE plans_trainings FROM locations Locations
The "last" problem seem only this part after AS counter:
AS (SELECT COUNT(plans_trainings__id) FROM plans_trainings, trainings,
projects WHERE plans_trainings
This is what the statement breaks!
Any ideas how to solve that?
If I run the statement in phpmyadmin and remove this mentioned part, the statement works fine and brings the right results!
UPDATE 2:
this is the plain statement:
select
locations.id,
locations.description,
(
select
count(plans_trainings.id)
from
plans_trainings,
trainings,
projects
where
plans_trainings.training_id = trainings.id
and projects.location_id = locations.id
and plans_trainings.project_id = projects.id
) as 'Anzahl'
from
locations;
try this in controller
$this->loadModel('Locations');
$this->loadModel('PlansTrainings');
$this->loadModel('Trainings');
$this->loadModel('Projects');
$sub_query=$this->PlansTrainings->find()->select(['cnt1'=>'count(PlansTrainings.id)'])->join([
[
'table' => 'trainings',
'alias' => 'Trainings',
'type' => 'INNER',
'conditions' => 'PlansTrainings.training_id=Trainings.id',
],
[
'table' => 'projects',
'alias' => 'Projects',
'type' => 'INNER', //LEFT, RIGHT...
'conditions' => ['Projects.location_id=PlansTrainings.id','PlansTrainings.project_id=Projects.id'],
],
]);
$locationsDiagramData = $this->Locations->find()->select(['id', 'description','count'=>$sub_query]);

Problems with SUM() and alias with CakePHP 3

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']

Convert the MySql query to CakePhp 2.0

How do I convert this MySql query to CakePhp's find.
And please tell me how can i practice writing Find queries in cakephp
select distinct trips.fk_userid from spots, trips
where spots.fk_tripid = trips.id
and trips.isapproved = 1
and spots.id in (".$row[$first_index]['spot_list'].")
The model can be Trip and you can query like this
$this->Trip->query("select distinct trips.fk_userid from spots, trips where spots.fk_tripid = trips.id and trips.isapproved = 1 and spots.id in (".$row[$first_index]['spot_list'].")");
or
You should create Trip and Spot model and in Trip model, you have to have this in Spot model:
public $belongsTo = array(
'Trip' => array(
'className' => 'Trip',
'foreignKey' => 'fk_tripid'
)
);
and query it like this:
$this->Spot->find('all', array(
'fields' => array("distinct Trip.fk_userid"),
'conditions' => array(
'Trip.isapproved' => 1,
'Spot.id' => $row[$first_index]['spot_list']
)
));

CakePHP counterCache joining irrelevant tables to update counter

I have a User model and a Message model.
The Message model is linked to the User model twice like this:
public $belongsTo = array(
'UserSender' => array(
'className' => 'User',
'foreignKey' => 'sender_id',
'counterCache' => array(
'messages_sent_count' => array(
'is_deleted' => FALSE
)
)
),
'UserRecipient' => array(
'className' => 'User',
'foreignKey' => 'recipient_id',
'counterCache' => array(
'messages_received_count' => array(
'is_deleted' => FALSE
),
'messages_unread_count' => array(
'is_deleted' => FALSE,
'is_read' => FALSE
)
)
),
'Operator' => array(
'className' => 'Operator',
'foreignKey' => 'operator_id'
)
);
Besides the User model, the Message model also $belongsTo the Operator model. The Operator model is irrelevant to the message count for the users, but its table is still being joined in the count query, as debug shows:
'query' => 'SELECT COUNT(*) AS `count` FROM `database`.`messages` AS `Message` LEFT JOIN `database`.`operators` AS `Operator` ON (`Message`.`operator_id` = `Operator`.`id`) LEFT JOIN `database`.`users` AS `UserSender` ON (`Message`.`sender_id` = `UserSender`.`id`) LEFT JOIN `database`.`users` AS `UserRecipient` ON (`Message`.`recipient_id` = `UserRecipient`.`id`) WHERE `Message`.`is_deleted` = '0' AND `Message`.`sender_id` = 389',
'params' => array(),
'affected' => (int) 1,
'numRows' => (int) 1,
'took' => (float) 394
For the sake of simplicity I've actually excluded one more model that the Message model $belongsTo, but the above query shows the problem.
The counterCache function does a quite expensive query just to update the counter. Is there a way to maybe override or adjust the counterCache method to not join irrelevant tables in the query?
I can't test it right now, but since the recursive setting used by Model::updateCounterCache() is hard-coded based on whether conditions are defined for the counter cache field, the only way to change this (besides completely reimplementing Model::updateCounterCache()) is probably to modify the count query in Model::_findCount() or Model::beforeFind() of your Message model.
public function beforeFind($query) {
// ... figure whether this is the count query for updateCounterCache,
// maybe even try to analyze whether the passed conditions require
// joins or not.
if(/* ... */) {
$query['recursive'] = -1;
}
return $query;
}
Depending on how much control you'll actually need the containable behavior might do the trick too, it sets recursive to -1 in case no containments are being passed
$Message->contain(); // === recursive is being set to -1 in before find callback
$Message->delete(123);

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.