CakePhp Too Many Identical Queries - cakephp-2.0

I have a complex Model with many containable.
However, when I run a query I see in my logs many similar queries:
SELECT `Company`.`id` FROM `u`.`companies` AS `Company` LEFT JOIN `u`.`companies` AS `Parent` ON (`Company`.`parent_id` = `Parent`.`id`) LEFT JOIN `u`.`groups` AS `Group` ON (`Company`.`group_id` = `Group`.`id`) WHERE 1 = 1 GROUP BY `Company`.`id` LIMIT 30
SELECT `Group`.`id`, `Group`.`name`, `Group`.`alias`, `Group`.`label` FROM ``.`groups` AS `Group` WHERE `Group`.`id` = 1
SELECT `Group`.`id`, `Group`.`name`, `Group`.`alias`, `Group`.`label` FROM `u`.`groups` AS `Group` WHERE `Group`.`id` = 4
SELECT `Group`.`id`, `Group`.`name`, `Group`.`alias`, `Group`.`label` FROM `u`.`groups` AS `Group` WHERE `Group`.`id` = 1
SELECT `Group`.`id`, `Group`.`name`, `Group`.`alias`, `Group`.`label` FROM `u`.`groups` AS `Group` WHERE `Group`.`id` = 1
SELECT `Group`.`id`, `Group`.`name`, `Group`.`alias`, `Group`.`label` FROM `u`.`groups` AS `Group` WHERE `Group`.`id` = 1
Why there are so many identical queries?
My query is very simple:
$this->paginate = array(
'Company' => array(
'contain' =>array(
'Group',
'Parent' => array(
'fields' => array('ragione')
),
'Parent.Group'
),
'limit' => 30,
'group' => array('Company.id'),
'conditions' => $conditions,
'order' => array('Company.created ASC')
)
);

Related

how to remove single quotes inside BETWEEN condition cakephp

I m trying to separated single quote from the values inside BETWEEN condition in cakephp 2 but it always gets values with single quotes like BETWEEN '2' and '34' .
here is my code:
$ref_no1 = $this->request->data['Lead']['ref_no1'];
$ref_no2 = $this->request->data['Lead']['ref_no2'];
$customerHo = $this-> Customer -> find('all',array(
'order' => array('Customer.customer_name' => 'asc'),
'joins'=>array(
array('table'=>'leads','alias'=>'Lead','type'=>'LEFT','foreignKey'=>false,'conditions'=>array('Customer.customer_id = Lead.customer_id')),
),
'fields'=>'Customer.*,Lead.*',
'conditions' => array(
'Customer.status' => 'active','Customer.customer_id Like'=>'S%',
'Customer.company_id'=>$company_id,
'AND' => array(
array('Lead.ref_no BETWEEN ? and ?' => array($ref_no1,$ref_no2) ),
),
)));
I am getting output like :
SELECT `Customer`.*, `Lead`.*
FROM `customers` AS `Customer`
LEFT JOIN `timezip_db_demo`.`leads` AS `Lead` ON (`Customer`.`customer_id` = `Lead`.`customer_id`)
WHERE `Customer`.`customer_id` Like 'S%' AND
`Lead`.`ref_no` BETWEEN '2' and '34'
ORDER BY `Customer`.`customer_name` asc
Expected output :
SELECT `Customer`.*, `Lead`.*
FROM `customers` AS `Customer`
LEFT JOIN `timezip_db_demo`.`leads` AS `Lead` ON (`Customer`.`customer_id` = `Lead`.`customer_id`)
WHERE `Customer`.`customer_id` Like 'S%' AND
`Lead`.`ref_no` BETWEEN 2 and 34
ORDER BY `Customer`.`customer_name` asc
can't you just do it like this? I didn't test this code yet.
$ref_no1 = $this->request->data['Lead']['ref_no1'];
$ref_no2 = $this->request->data['Lead']['ref_no2'];
$customerHo = $this-> Customer -> find('all',array(
'order' => array('Customer.customer_name' => 'asc'),
'joins'=>array(
array('table'=>'leads','alias'=>'Lead','type'=>'LEFT','foreignKey'=>false,'conditions'=>array('Customer.customer_id = Lead.customer_id')),
),
'fields'=>'Customer.*,Lead.*',
'conditions' => array(
'Customer.status' => 'active','Customer.customer_id Like'=>'S%',
'Customer.company_id'=>$company_id,
'AND' => array(
array('Lead.ref_no BETWEEN' . $ref_no1 . 'and' . $ref_no2 ),
),
)));
you can convert that string into integer, i hope it will work
array((int)$ref_no1,(int)$ref_no2)

Joining two models in a paginate

I have two tables that I want to join in the controller..
The paginate model also have a lot of conditions but I wanted to simplify it in here.
$Table = $this->Table->query('
SELECT Table.id FROM Table
INNER JOIN TableA ON Table.id = TableA.table_id
INNER JOIN TableA.Table_id = TabelB.id
WHERE
IFNULL(Table.x,0) <> 0
GROUP BY Table.id
HAVING COUNT(*) > 1');
$this->paginate = array(
'paramType' => 'querystring'
,'joins' => $Table
)
);
I'm nto that comfortable with Cake, coming more from a SQL background , but can this be done in the controller or is it that this should go in the Model ?
$UserId = $this->Auth->user(id);
$this->Rate->bindModel(array('belongsTo'=>array('Vehicle'=>array('className'=>'Vehicle','foreignKey'=>'vehicle_id'),),),false);
$this->paginate = array('conditions'=>array('Rate.user_id'=>$UserId),
'order' => array('Rate.created DESC'),
'limit' =>'2'
);
$rating = $this->paginate('Rate');
As I answered in a identical question in "Controller pagination with a subquery" here's the same answer for this question
$this->paginate = array(
'paramType' => 'querystring',
'joins' => array(
array(
'table' => '(SELECT Table.id
FROM Table
INNER JOIN TableA ON Table.id = TableA.Table_id
INNER JOIN TableB ON TableA.TableB_id = TableB.id
WHERE
1 = 1
GROUP BY Table.id
HAVING COUNT(*) = 1)'
'alias' => 'Table_x',
'type' => 'INNER',
'conditions' => array('Table_x.id = Table.id')
)
)
);
$Table = $this->paginate();

I want Cakephp code in my query

I am Cakephp Beginner.
I want this query with cakephp..
Original Query..
SELECT `Advertisement`.*, `Gallery`.`image` FROM `moenatmi_moen`.`advertisements`
AS `Advertisement` LEFT JOIN `moenatmi_moen`.`galleries` AS `Gallery` ON
(`Gallery`.`advertise_id` = `Advertisement`.`id` AND `Gallery`.`main_ad_image`
= 1) WHERE `Advertisement`.`status` = 1 AND `Advertisement`.`category_id` = 14 AND
((`Advertisement`.`expiry_date` >= '2014-11-18') OR (`Advertisement`.`expiry_date`
IS NULL)) GROUP BY `Advertisement`.`id` ORDER BY `Advertisement`.`id` desc
LIMIT 10
I Want Like this query..
SELECT `Advertisement`.*, `Gallery`.`image` FROM `moenatmi_moen`.`advertisements`
AS `Advertisement` LEFT JOIN `moenatmi_moen`.`galleries` AS `Gallery` ON
(`Gallery`.`advertise_id` = `Advertisement`.`id` AND `Gallery`.`main_ad_image` = 1)
WHERE `Advertisement`.`status` = 1 AND `Advertisement`.`category_id` IN (select id from
categories where id=14 or parent_id=14) AND ((`Advertisement`.`expiry_date` >=
'2014-11-18') OR (`Advertisement`.`expiry_date` IS NULL)) GROUP BY
`Advertisement`.`id` ORDER BY `Advertisement`.`id` desc LIMIT 10
Original Cakephp Code..
$this->paginate['conditions'] = array(
'Advertisement.status'=>1,
'Advertisement.category_id'=>$cat_id,
'OR'=>array(
'Advertisement.expiry_date >='=>date('Y-m-d'),
'Advertisement.expiry_date'=>null
)
);
Help me..
Thanks You..
this should be a painless switch. This first query calls the category ids that you're wanting within your main query.
$cat_id is the same variable you're using in the original query.
$ids = $this->Category->find('all', array(
'conditions' => array(
'id' => $cat_id,
'parent_id' => $cat_id
)
)
);
The important thing to note here, this query will output your typical nested array..
array(
array(),
array(),
array()
);
The classicExtract function will sift through the mess for you and give you a single array with a list of 'id' which is exactly what you want for your query. EX:
array(14, 15, 16, 18, 19);
Finally, your main query.
$this->paginate['conditions'] = array(
'Advertisement.status'=>1,
'Advertisement.category_id'=> Set::classicExtract($ids, '{n}.Category.id'),
'OR'=>array(
'Advertisement.expiry_date >=' => date('Y-m-d'),
'Advertisement.expiry_date'=>null
)
);
Conclusion
All together your new conditions will look just like this:
$ids = $this->Category->find('all', array(
'conditions' => array(
'id' => $cat_id,
'parent_id' => $cat_id
)
)
);
$this->paginate['conditions'] = array(
'Advertisement.status'=>1,
'Advertisement.category_id'=> Set::classicExtract($ids, '{n}.Category.id'),
'OR'=>array(
'Advertisement.expiry_date >=' => date('Y-m-d'),
'Advertisement.expiry_date'=>null
)
);

CakePHP distinct picks extra column

i'm working on a project in CakePHP but stuck at a strange problem. I'm writing a query:
$brands = $this->Product->find('all', array(
'fields'=> array('DISTINCT Product.brand as brand'),
'order'=>'Product.brand ASC',
'conditions'=> array('Product.subcategory_id'=>$subcategory_id)
));
It is picking Product.id along with Product.brand which I do not want.
The query it generates is:
SELECT DISTINCT `Product`.`brand`, `Product`.`id` FROM `ecom`.`products` AS `Product` LEFT JOIN `ecom`.`subcategories` AS `SubCategory` ON (`Product`.`subcategory_id` = `SubCategory`.`id`) LEFT JOIN `ecom`.`categories` AS `Category` ON (`Product`.`category_id` = `Category`.`id`) WHERE `Product`.`subcategory_id` = 13 ORDER BY `Product`.`brand` ASC
How can I skip Product.id from select?
Thanks
Adding group solved my issue:
$brands = $this->Product->find('all', array(
'fields'=> array('DISTINCT Product.brand as brand'),
'order'=>'Product.brand ASC',
'conditions'=> array('Product.subcategory_id'=>$subcategory_id),
'group' => 'brand'
));
I think it's because cake needs the id to create the joins
try
$brands = $this->Product->find('all', array(
'fields'=> array('DISTINCT Product.brand as brand'),
'order'=>'Product.brand ASC',
'conditions'=> array('Product.subcategory_id'=> $subcategory_id),
'recursive' => -1
));

cakephp 'contain' left joint does not use specified foreignKey for left join

On cakephp 2.1, I have two tables: qca belongs to employee via field emp_number on both tables.
qca model belongsTo : (pleae note foreignKey)
public $actsAs = array('Containable');
var $belongsTo = array('Dir',
'Employee' => array(
'className' => 'Employee',
'foreignKey' => 'emp_number')
);
employee model:
public $actsAs = array('Containable');
On my controller's find, i use 'contain' to retrieve employee info based on emp_number from qca table.
$hoursvalues = $this->Qca->find('all', array('conditions' => $conditions,
'fields' => array('Qca.emp_number', 'Sum(CASE WHEN Qca.qca_tipcode = 1 THEN 1 END) AS Qca__comps', 'Sum(qca_end - qca_start) as Qca__production', 'Sum(Qca.qca_durend) as Qca__idle'),
'contain' => array(
'Employee' => array(
'fields' => array('emp_number', 'emp_ape_pat', 'emp_ape_mat', 'emp_ape_mat'))),
'group' => array('Qca.emp_number'),
));
However, the executed sql sentence shows:
LEFT JOIN `devopm`.`employees` AS `Employee` ON (`Qca`.`emp_number` = `Employee`.`id`)
Whereas
Employee.id should be Employee.emp_number
This is the full sql sentence:
SELECT `Qca`.`emp_number`, Sum(CASE WHEN Qca.qca_tipcode = 1 THEN 1 END) AS Qca__comps, Sum(qca_end - qca_start) as Qca__production, Sum(`Qca`.`qca_durend`) as Qca__idle, `Employee`.`emp_number`, `Employee`.`emp_ape_pat`, `Employee`.`emp_ape_mat`, `Employee`.`id` FROM `devopm`.`qcas` AS `Qca` LEFT JOIN `devopm`.`employees` AS `Employee` ON (`Qca`.`emp_number` = `Employee`.`id`) WHERE `Qca`.`dir_id` = 63 AND FROM_UNIXTIME(`Qca`.`qca_start`, '%Y-%m-%d') >= '2012-07-18' AND FROM_UNIXTIME(`Qca`.`qca_start`, '%Y-%m-%d') <= '2012-07-18' GROUP BY `Qca`.`emp_number`
This results on null values returned for Employee:
array(
(int) 0 => array(
'Qca' => array(
'emp_number' => 'id3108',
'comps' => '2',
'production' => '7784',
'idle' => '529'
),
'Employee' => array(
'emp_ape_pat' => null,
'emp_ape_mat' => null,
'id' => null
)
),
Note: I have other instance of 'contain' working (one with default id = tableName.id). I'm wondering if the foreignKey on belongsTo ('foreignKey' => 'emp_number') is just not good for 'contain' to work?
Can you help?
Thank you so much.
(I found a workaround but slows down the query a great deal (it duplicates the left join and takes forever)
$joins = array(
array('table' => 'publication_numerations',
'alias' => 'PublicationNumeration',
'type' => 'LEFT',
'conditions' => array(
'Publication.id = PublicationNumeration.publication_id',
)
)
);
$this->Publication->find('all', array('joins' => $joins));

Resources