How to do UNION query with PHP CodeIgniter framework's active record query format?
CodeIgniter's ActiveRecord doesn't support UNION, so you would just write your query and use the ActiveRecord's query method.
$this->db->query('SELECT column_name(s) FROM table_name1 UNION SELECT column_name(s) FROM table_name2');
By doing union using last_query(), it may hamper performance of application. Because for single union it would require to execute 3 queries. i.e for "n" union "n+1" queries. It won't much affect for 1-2 query union. But it will give problem if union of many queries or tables having large data.
This link will help you a lot: active record subqueries
We can combine active record with manual queries.
Example:
// #1 SubQueries no.1 -------------------------------------------
$this->db->select('title, content, date');
$this->db->from('mytable');
$query = $this->db->get();
$subQuery1 = $this->db->_compile_select();
$this->db->_reset_select();
// #2 SubQueries no.2 -------------------------------------------
$this->db->select('title, content, date');
$this->db->from('mytable2');
$query = $this->db->get();
$subQuery2 = $this->db->_compile_select();
$this->db->_reset_select();
// #3 Union with Simple Manual Queries --------------------------
$this->db->query("select * from ($subQuery1 UNION $subQuery2) as unionTable");
// #3 (alternative) Union with another Active Record ------------
$this->db->from("($subQuery1 UNION $subQuery2)");
$this->db->get();
This is a quick and dirty method I once used
// Query #1
$this->db->select('title, content, date');
$this->db->from('mytable1');
$query1 = $this->db->get()->result();
// Query #2
$this->db->select('title, content, date');
$this->db->from('mytable2');
$query2 = $this->db->get()->result();
// Merge both query results
$query = array_merge($query1, $query2);
Not my finest work, but it solved my problem.
note: I didn't need to order the result.
You may use the following method to get the SQL statement in the model:
$this->db->select('DISTINCT(user_id)');
$this->db->from('users_master');
$this->db->where('role_id', '1');
$subquery = $this->db->_compile_select();
$this->db->_reset_select();
This way the SQL statement will be in the $subquery variable, without actually executing it.
You have asked this question a long time ago, so maybe you have already got the answer. if not, this process may do the trick.
by modifying somnath huluks answer, i add these following variable and functions to DB_Active_rec class as follows:
class DB_Active_records extends CI_DB_Driver
{
....
var $unions;
....
public function union_push($table = '')
{
if ($table != '')
{
$this->_track_aliases($table);
$this->from($table);
}
$sql = $this->_compile_select();
array_push($this->unions, $sql);
$this->_reset_select();
}
public function union_flush()
{
$this->unions = array();
}
public function union()
{
$sql = '('.implode(') union (', $this->unions).')';
$result = $this->query($sql);
$this->union_flush();
return $result;
}
public function union_all()
{
$sql = '('.implode(') union all (', $this->unions).')';
$result = $this->query($sql);
$this->union_flush();
return $result;
}
}
therefore you can virtually use unions without dependencies to db_driver.
to use union with this method, you simply make regular active record queries, but calling union_push instead of get.
note: you have to ensure your queries have matching columns like regular unions
example:
$this->db->select('l.tpid, l.lesson, l.lesson_type, l.content, l.file');
$this->db->where(array('l.requirement' => 0));
$this->db->union_push('lessons l');
$this->db->select('l.tpid, l.lesson, l.lesson_type, l.content, l.file');
$this->db->from('lessons l');
$this->db->join('scores s', 'l.requirement = s.lid');
$this->db->union_push();
$query = $this->db->union_all();
return $query->result_array();
would produce:
(SELECT `l`.`tpid`, `l`.`lesson`, `l`.`lesson_type`, `l`.`content`, `l`.`file`
FROM `lessons` l
WHERE `l`.`requirement`=0)
union all
(SELECT `l`.`tpid`, `l`.`lesson`, `l`.`lesson_type`, `l`.`content`, `l`.`file`
FROM `lessons` l
JOIN `scores` s ON `l`.`requirement`=`s`.`lid`)
I found this library, which worked nicely for me to add UNION in an ActiveRecord style:
https://github.com/NTICompass/CodeIgniter-Subqueries
BUT I had to grab the get_compiled_select() method from the dev branch of CodeIgniter first (available here: https://github.com/EllisLab/CodeIgniter/blob/develop/system/database/DB_query_builder.php -- DB_query_builder will be replacing DB_active_rec). Presumably this method will be available in a future production release of CodeIgniter.
Once I added that method to DB_active_rec.php in system/database it worked like a charm. (I didn't want to use the dev version of CodeIgniter as this is a production app.)
try this one
function get_merged_result($ids){
$this->db->select("column");
$this->db->distinct();
$this->db->from("table_name");
$this->db->where_in("id",$model_ids);
$this->db->get();
$query1 = $this->db->last_query();
$this->db->select("column2 as column");
$this->db->distinct();
$this->db->from("table_name");
$this->db->where_in("id",$model_ids);
$this->db->get();
$query2 = $this->db->last_query();
$query = $this->db->query($query1." UNION ".$query2);
return $query->result();
}
This is solution I am using:
$union_queries = array();
$tables = array('table1','table2'); //As much as you need
foreach($tables as $table){
$this->db->select(" {$table}.row1,
{$table}.row2,
{$table}.row3");
$this->db->from($table);
//I have additional join too (removed from this example)
$this->db->where('row4',1);
$union_queries[] = $this->db->get_compiled_select();
}
$union_query = join(' UNION ALL ',$union_queries); // I use UNION ALL
$union_query .= " ORDER BY row1 DESC LIMIT 0,10";
$query = $this->db->query($union_query);
bwisn's answer is better than all and will work but not good in performance because it will execute sub queries first.
get_compiled_select does not run query; it just compiles it for later run so is faster
try this one
$this->db->select('title, content, date');
$this->db->where('condition',value);
$query1= get_compiled_select("table1",FALSE);
$this->db->reset_query();
$this->db->select('title, content, date');
$this->db->where('condition',value);
$query2= get_compiled_select("table2",FALSE);
$this->db->reset_query();
$query = $this->db->query("$query1 UNION $query2");
Here's a solution I created:
$query1 = $this->db->get('Example_Table1');
$join1 = $this->db->last_query();
$query2 = $this->db->get('Example_Table2');
$join2 = $this->db->last_query();
$union_query = $this->db->query($join1.' UNION '.$join2.' ORDER BY column1,column2);
I have the code like this
$phql = "SELECT COUNT(a.id) FROM UserParkingIn a JOIN UserVehicle b ON a.userVehicleId = b.id WHERE b.vehicleTypeId = 1";
$result = $this->modelsManager->executeQuery($phql);
echo $result;
in UserParkingIn Table I have example id = 10, userVehicleId = 2
in UserVehicle Table I have example id =10, userVehicleId = 2, vehicleTypeId = 1
It return empty, but when I execute this query in phpMyAdmin I use this sql logic it return right number.
SELECT COUNT(a.id) FROM user_parking_in a JOIN user_vehicle b ON a.userVehicleId = b.id WHERE b.vehicleTypeId=1;
and it return number 7
Can someone explain why this return error?
Thank you.
I found the solution that id I used to count must set an alias to be like quota like this.
$query = $this->modelsManager->createQuery("SELECT COUNT(a.id) as quota FROM UserParkingIn a JOIN UserVehicle b ON a.userVehicleId = b.id WHERE a.ospoId = '$ospoId' ");
$records = $query->execute();
foreach($records as $record){
$parkingUsed = $record->quota;
}
and now it is working.
I've two categories and I want to fetch three records of each category later I found this link UNION query with codeigniter's active record pattern after this I change my DB_Active_rec file and add this code also
var $unions = array();
public function union_push($table = '') {
if ($table != '') {
$this->_track_aliases($table);
$this->from($table);
}
$sql = $this->_compile_select();
array_push($this->unions, $sql);
$this->_reset_select();
}
public function union_flush() {
$this->unions = array();
}
public function union() {
$sql = '(' . implode(') union (', $this->unions) . ')';
$result = $this->query($sql);
$this->union_flush();
return $result;
}
public function union_all() {
$sql = '(' . implode(') union all (', $this->unions) . ')';
$result = $this->query($sql);
$this->union_flush();
return $result;
}
and then I create codeigniter's function based query like this
$this->db->select("*");
$this->db->from("media m");
$this->db->join("category c", "m.category_id=c.id", "INNER");
$this->db->order_by("m.media_files", "DESC");
$this->db->limit(3);
$this->db->union_push();
$this->db->select("*");
$this->db->from("media m");
$this->db->join("category c", "m.category_id=c.id", "INNER");
$this->db->order_by("m.media_files", "DESC");
$this->db->limit(3);
$this->db->union_push();
$getMedia = $this->db->union_all();
create this
(SELECT * FROM media m INNER JOIN category c ON
m.category_id = c.id ORDER BY m.media_files DESC LIMIT 3)
UNION ALL
(SELECT * FROM media m INNER JOIN category c ON
m.category_id = c.id ORDER BY m.media_files DESC LIMIT 3)
Now it is fetching records but not properly I want to use only query, it showing six records first query fetch 3 records and second query fetch three records now records are duplicate I check the id of records it is 6,5,4 and again 6,5,4. It can be done also by PHP but I want to use query. Thanks in advance
I dont know code-igniter, but basicly you want it to do the union first and then apply the order by over the whole set. This would require a subquery. It should result in the following SQL query:
select * from
((SELECT * FROM media m INNER JOIN category c ON m.category_id = c.id )
UNION ALL
(SELECT * FROM media m INNER JOIN category c ON m.category_id = c.id)) T
ORDER BY m.media_files DESC LIMIT 3
Hope it helps you some.
I'm trying to join two tables which share a common id, and it keeps returning a single row multiple times. Am working with codeigniter
This is the function from the model:
function get_latest_pheeds() {
$data = $this->user_keywords($this->ion_auth->user_id);
$keyword = $data;
$user_id = $this->ion_auth->user_id;
foreach($keyword as $key => $word) {
$q = "SELECT *,COUNT(pheed_comments.comment_id) as comments
FROM pheeds
LEFT JOIN pheed_comments ON pheed_comments.P_id=pheeds.pheed_id
WHERE pheed LIKE '%$word%' OR user_id='$user_id'
ORDER BY datetime DESC";
$result = $this->db->query($q);
$rows[] = $result->result();
}
return $rows;
}
Is my query wrong?
You are missing a GROUP BY for your COUNT()
$q = "SELECT *,COUNT(pheed_comments.comment_id) as comments
FROM pheeds
LEFT JOIN pheed_comments ON pheed_comments.P_id=pheeds.pheed_id
WHERE pheed LIKE '%$word%' OR user_id='$user_id'
GROUP BY pheed_id, pheed
ORDER BY datetime DESC";
Now, since you are using SELECT *, there may be more columns returned with the COUNT(). For accurate results, you also must list them in the GROUP BY:
GROUP BY pheed_id, pheed, othercol1, othercol2, othercol3
I want to generate the following SQL:
SELECT `rc`.*, `c`.`name` FROM `RunConfigurations` AS `rc` INNER JOIN `Clients` AS `c` ON rc.client_id = c.id WHERE (rc.client_id = ?) ORDER BY `rc`.`config_name` ASC
However I am getting:
SELECT `rc`.*, `c`.* FROM `RunConfigurations` AS `rc` INNER JOIN `Clients` AS `c` ON rc.client_id = c.id WHERE (rc.client_id = ?) ORDER BY `rc`.`config_name` ASC
The difference is I want c.name, not c.*
Using the following ZF PHP code:
public function fetchConfigurations($clientId = null, $order = 'rc.config_name ASC')
{
$db = $this->getDb();
$stmt = $db->select()
->from(array('rc' => 'RunConfigurations','c.name'))
->join(array('c' => 'Clients'),'rc.client_id = c.id')
->order($order);
if(is_numeric($clientId))
{
$stmt->where('rc.client_id = ?')
->bind(array($clientId));
}
$results = $db->fetchAll($stmt);
if(sizeof($results) > 0)
{
$configs = array();
foreach($results as $row)
{
$configs[] = $this->createRunConfigurationFromRow($row);
}
return $configs;
}
else
{
die($stmt->__toString());
return null;
}
}
This is aggravating and I feel like I am missing something at either:
->from(array('rc' => 'RunConfigurations','c.name'))
or
->join(array('c' => 'Clients'),'rc.client_id = c.id')
and the ZF examples are not shedding any light on this.
You are so close! join() actually has a 3rd parameter in which you can supply the column names just like the 2nd parameter from from().
This would mean that ->join(array('c' => 'Clients'),'rc.client_id = c.id',array('name')) should generate the SQL you are looking for.
-- Quote from the Zend Framework manual:
The third argument to join() is an array of column names, like that used in the from() method. It defaults to "*", supports correlation names, expressions, and Zend_Db_Expr in the same way as the array of column names in the from() method.