Reputation: 10634
Can someone help me convert this to an active record script?
I'm trying to get the email address and contact name from another table. map_userfields
table is a many-to-many table. Multiple rows relate to a single p.id
. Isolating specific fieldvalue data is done by searching for p.id
in conjunction with uf.fieldid
.
See this screenshot for a reference to the map_userfields table:
My current raw SQL:
SELECT
p.id,
(SELECT uf.fieldvalue FROM map_userfields uf WHERE uf.pointid = p.id AND uf.fieldid = 20) As ContactName,
(SELECT uf.fieldvalue FROM map_userfields uf WHERE uf.pointid = p.id AND uf.fieldid = 31) As ContactEmail
FROM map_points p
WHERE
/** $pointCategory is an array of categories to look for **/
p.type IN($pointCategory)
Note: I am using CodeIgniter 2.1.x, MySQL 5.x, php 5.3
Upvotes: 1
Views: 2428
Reputation: 47883
I will strongly urge you to not execute subqueries in the SELECT clause because this tends to be a very poor performer.
Instead, I'll demonstrate how to use a pivot query on your map_userfields table to set up a very convenient JOIN query. For your project, it will be very valuable to embrace the pivot technique when accessing map_userfields data.
$pointCategory = ['type1', 'type2']; // some made-up data
$pivot = $this->db->select([
'uf.pointid',
'MAX(CASE WHEN uf.fieldid = 20 THEN uf.fieldvalue END) contact_name',
'MAX(CASE WHEN uf.fieldid = 31 THEN uf.fieldvalue END) contact_email'
])
->group_by('uf.pointid')
->get_compiled_select('map_userfields uf');
return $this->db->select('p.id, uf_pivot.contact_name, uf_pivot.contact_email')
->join("($pivot) uf_pivot", 'p.id = uf_pivot.pointid', 'LEFT')
->where_in('p.type', $pointCategory)
->get('map_points p')
->result();
The rendered SQL (with improved spacing for readability)
SELECT `p`.`id`,
`uf_pivot`.`contact_name`,
`uf_pivot`.`contact_email`
FROM `map_points` `p`
LEFT JOIN (
SELECT `uf`.`pointid`,
MAX(CASE WHEN uf.fieldid = 20 THEN uf.fieldvalue END) contact_name,
MAX(CASE WHEN uf.fieldid = 31 THEN uf.fieldvalue END) contact_email
FROM `map_userfields` `uf`
GROUP BY `uf`.`pointid`
) uf_pivot ON `p`.`id` = `uf_pivot`.`pointid`
WHERE `p`.`type` IN('type1', 'type2')
You'll see that the MAX() expressions in the pivot subquery isn't fully quoted, but this is a harmless outcome for this query. If you wish to manually escape/quote the entities/values, CI has methods for this, but you'll need to muddy-up these expressions with verbose concatenation or interpolation.
result()
will return an array of zero or more objects.
A LEFT JOIN is used to enable the possibility of returning rows where p.id is not actually found in the pivot subquery.
If the pivot subquery doesn't find a fieldvalue with fieldid 20 or 31, you'll get null
values for contact_name
and contact_email
in the result set -- just something to be aware of.
More refinement could be added to the pivot subquery involving WHERE and HAVING conditions, but I decided to keep the script simple.
Upvotes: 1
Reputation: 19882
Sub queries indeed work in codeigniter but there is a little hack. I found that in in system/database/DB_active_rec.php there are two functions named _compile_select and _reset_select. If you remove the protected word from both you will be able to use these function for subqueries Here is a usage tutorial
http://heybigname.com/2009/09/18/using-code-igniters-active-record-class-to-create-subqueries/
Upvotes: 0
Reputation: 19466
CodeIgniter's Active Record doesn't support subqueries out-of-the-box. You'll need to download the CodeIgniter Subqueries class.
In the CodeIgniter wiki, there's an article on how to subqueries.
Upvotes: 2
Reputation: 9006
You can select anything you need with CI's activeRecords as long as you tell CI not to parse your string
$this->db->select('p.id,
(SELECT uf.fieldvalue FROM map_userfields uf WHERE uf.pointid = p.id AND uf.fieldid = 20) As ContactName,
(SELECT uf.fieldvalue FROM map_userfields uf WHERE uf.pointid = p.id AND uf.fieldid = 31) As ContactEmail
',TRUE);
$this->db->from('map_points p');
$this->db->where_in('p.type',$pointCategory);
$q = $this->db->get();
Upvotes: 1