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();
Related
How do you convert the following SQL Query to a CakePhp Find Query?
SELECT
a.id, a.rev, a.contents
FROM
YourTable a
INNER JOIN (
SELECT
id, MAX(rev) rev
FROM
YourTable
GROUP BY
id
) b ON a.id = b.id AND a.rev = b.rev
I have tried the code below:
return $model->find('all', [
'fields' => $fields,
'joins' => [
[
'table' => $model->useTable,
'fields' => ['id','MAX(rev) as rev'],
'alias' => 'max_rev_table',
'type' => 'INNER',
'group' => ['id'],
'conditions' => [
$model->name.'.id= max_rev_table.id',
$model->name.'.rev = max_rev_table.rev'
]
]
],
'conditions' => [
$model->name.'.emp_id' => $empId
]
]);
But it seems that in the generated SQL, the fields under the joins is not included. So I don't get the max(rev) which I need to get only the rows with max(rev).
I have tried rearranging the items inside joins but still produces same auto-generated SQL.
Can you please help me?
There are no fields or group options for joins, the only options are table, alias, type, and conditions.
If you want to join a subquery, then you need to explicitly generate one:
$ds = $model->getDataSource();
$subquery = $ds->buildStatement(
array(
'fields' => array('MaxRev.id', 'MAX(rev) as rev'),
'table' => $ds->fullTableName($model),
'alias' => 'MaxRev',
'group' => array('MaxRev.id')
),
$model
);
and pass it to the joins table option:
'table' => "($subquery)"
See also
Cookbook > Models > Associations: Linking Models Together > Joining tables
Cookbook > Models > Retrieving Your Data > Sub-queries
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')
)
);
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
)
);
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
));
I have these tables and the relationships between them:
1 project hasmany configurationcontext 1 issuetype hasmany
optionconfiguration hasmany configurationcontext hasmany
optionconfiguration (does not exist intermediate table)
My goal is to get information like this query.
SELECT IT.id, IT.pname
FROM configurationcontext CC
LEFT OUTER JOIN optionconfiguration OC ON OC.fieldconfig = CC.fieldconfigscheme
LEFT OUTER JOIN issuetype IT ON IT.id = OC.optionid
WHERE CC.project = 10000
my doubts:
- which the controller to use to create a function that return me this information?
- How do I get this information?
thanks :)
Assuming I have your model names correct, this should do the trick:
$this->ConfigurationContext->find('all', array(
'joins' => array(
array(
'table' => 'optionconfiguration',
'alias' => 'OptionConfiguration',
'type' => 'LEFT OUTER JOIN',
'conditions' => array(
'OptionConfiguration.fieldconfig = ConfigurationContext.fieldconfigscheme'
)
),
array(
'table' => 'issuetype',
'alias' => 'IssueType',
'type' => 'LEFT OUTER JOIN',
'conditions' => array(
'IssueType.id = OptionConfiguration.optionid'
)
)
),
'conditions' => array(
'ConfigurationContext.project' => 10000
),
'fields' => array(
'IssueType.id',
'IssueType.pname'
)
));
I haven't tried type "LEFT OUTER JOIN" but I don't see why it wouldn't work, maybe look into using containable to avoid using joins if you can.