Reputation: 193
I have this raw MySQL query; how can I make this an active record query?
SELECT
chp_id,
chp_destination,
cde_name,
chp_year,
chp_from,
chp_to,
chp_budget_price_high,
chp_medium_price_high,
chp_luxury_price_high,
chp_budget_price_low,
chp_medium_price_low,
chp_luxury_price_low,
chp_timestamp,
chp_comment
FROM crm_hotel_price
LEFT JOIN crm_destinations ON cde_id = chp_destination
WHERE chp_id IN
(
SELECT MAX( chp_id )
FROM crm_hotel_price
GROUP BY chp_destination, chp_year
)
ORDER BY
chp_id
Upvotes: 1
Views: 100
Reputation: 47883
Modern CodeIgniter does allow for subqueries to be compiled separately/safely and saved as a string to be inserted into a parent query. This subquery can be passed into where_in()
so long as the the escaping parameter is turned off.
$destYearMaxIds = $this->db
->select_max('chp_id')
->group_by(['chp_destination', 'chp_year'])
->get_compiled_select('crm_hotel_price');
return $this->db
->select([
'chp_id',
'chp_destination',
'cde_name',
'chp_year',
'chp_from',
'chp_to',
'chp_budget_price_high',
'chp_medium_price_high',
'chp_luxury_price_high',
'chp_budget_price_low',
'chp_medium_price_low',
'chp_luxury_price_low',
'chp_timestamp',
'chp_comment'
])
->join('crm_destinations', 'crm_destinations.cde_id = crm_hotel_price.chp_destination', 'LEFT')
->where_in('chp_id', $destYearMaxIds, false)
->order_by('chp_id')
->get('crm_hotel_price')
->result();
Rendered SQL:
SELECT `chp_id`, `chp_destination`, `cde_name`, `chp_year`, `chp_from`, `chp_to`, `chp_budget_price_high`, `chp_medium_price_high`, `chp_luxury_price_high`, `chp_budget_price_low`, `chp_medium_price_low`, `chp_luxury_price_low`, `chp_timestamp`, `chp_comment`
FROM `crm_hotel_price`
LEFT JOIN `crm_destinations` ON `crm_destinations`.`cde_id` = `crm_hotel_price`.`chp_destination`
WHERE chp_id IN(
SELECT MAX(`chp_id`) AS `chp_id`
FROM `crm_hotel_price`
GROUP BY `chp_destination`, `chp_year`
)
ORDER BY `chp_id`
A word of caution though, a subquery inside of an IN condition should probably be replaced with a JOIN on a subquery for performance reasons.
SELECT
p.chp_id,
p.chp_destination,
d.cde_name,
p.chp_year,
p.chp_from,
p.chp_to,
p.chp_budget_price_high,
p.chp_medium_price_high,
p.chp_luxury_price_high,
p.chp_budget_price_low,
p.chp_medium_price_low,
p.chp_luxury_price_low,
p.chp_timestamp,
p.chp_comment
FROM crm_hotel_price p
LEFT JOIN crm_destinations d ON d.cde_id = p.chp_destination
JOIN (
SELECT
MAX(chp_id) max_chp_id,
chp_destination,
chp_year
FROM crm_hotel_price
GROUP BY chp_destination, chp_year
) max_p ON p.chp_id = max_p.max_chp_id
ORDER BY p.chp_id;
This can be achieved with:
$destYearMaxId = $this->db
->select([
'MAX(chp_id) max_chp_id',
'chp_destination',
'chp_year'
])
->group_by(['chp_destination', 'chp_year'])
->get_compiled_select('crm_hotel_price');
return $this->db
->select([
'p.chp_id',
'p.chp_destination',
'd.cde_name',
'p.chp_year',
'p.chp_from',
'p.chp_to',
'p.chp_budget_price_high',
'p.chp_medium_price_high',
'p.chp_luxury_price_high',
'p.chp_budget_price_low',
'p.chp_medium_price_low',
'p.chp_luxury_price_low',
'p.chp_timestamp',
'p.chp_comment'
])
->join('crm_destinations d', 'd.cde_id = p.chp_destination', 'LEFT')
->join("($destYearMaxId) max_p", 'p.chp_id = max_p.max_chp_id')
->order_by('p.chp_id')
->get('crm_hotel_price p')
->result();
Upvotes: 0
Reputation: 6016
Yes subquery is not yet supported by active record and you can't extend the class easily. So you want to do something like this (not tested)
$this->db->select('chp_id')
->select('chp_destination')
->select('cde_name')
->select('chp_year')
->select('chp_from')
->select('chp_to')
->select('chp_budget_price_high')
->select('chp_medium_price_high')
->select('chp_luxury_price_high')
->select('chp_budget_price_low')
->select('chp_medium_price_low')
->select('chp_luxury_price_low')
->select('chp_timestamp')
->select('chp_comment')
->from('crm_hotel_price')
->join('crm_destinations', 'cde_id = chp_destination', 'left')
->where('chp_id IN (SELECT MAX( chp_id ) FROM crm_hotel_price GROUP BY chp_destination, chp_year)')
->order_by('chp_id');
$query = $this->db->get();
Upvotes: 1