10

I am working on a search functionality. I have created a search form in which user can search an Application based on Type,ope & Formate.

I have used a subquery in my join query to get the desired result. I have tested my query in MySQL Workbench nad it's working fine.

But when I tried that same query in Codeigniter using query builder technique then I am facing a problem.

Here is the query which is worked fine in workbench:

SELECT (*)
FROM `App`
LEFT JOIN `App_type` 
ON `App_type`.`app_id` = `App`.`id`
LEFT JOIN `App_formate` 
ON `App_formate`.`app_id` = `App`.`id`
WHERE `App`.`id` IN(select app_id FROM App_type WHERE type_id in (3,2,6) group by app_id HAVING COUNT(*) = 3)
AND `App_formate`.`formate_id` IN('1', '3')
AND `jobs`.`ope_min` <= '3'
AND `jobs`.`ope_max` >= '3'
GROUP BY `jobs`.`id`;

This is the join query which I use:

$subquery = "select app_id FROM App_type WHERE type_id in ($selected_type) group by app_id HAVING COUNT(*) = $type_count";

$search_app_query = $this->db
    ->select('*')
    ->from('App')
    ->join('App_type', 'App_type.app_id = App.id', 'left outer')
    ->join('App_formate', 'App_formate.app_id = App.id', 'left outer')      
    ->where_in('App.id',$subquery)  //<-- Here is the problem
    ->where_in('App_formate.formate_id',$data['selected_formates'])
    ->where('App.ope_min <=',$data['ope_value'])
    ->where('App.ope_max >=',$data['ope_value'])    
    ->group_by("App.id", "desc")
    ->get();

While I am debugging this problem it shows the

 I have found the problem is in this part of the query:
 "WHERE `App`.`id` IN('select app_id 
 FROM App_type 
 WHERE type_id in (3,2,6) 
 group by app_id HAVING COUNT(*) = 3')"

that single quote in this subquery is creating a problem.

What I have tried so far:

To remove this single quote I have tried

  1. REPLACE($subquery, '''', '')
  2. ->where_in('App.id',trim($subquery,"'"))
  3. $subquery_improved = substr($subquery, 1, -1);

But all this solution is not working. They are not removing the single quote.

Note: I am aware of $this->db->query() but do not want to use that.

yAnTar
  • 4,269
  • 9
  • 47
  • 73
always-a-learner
  • 3,671
  • 10
  • 41
  • 81
  • 1
    I'm not familiar with the framework -- particularly how to pass that subquery in as an **actual subquery.** But, if the docs don't make it clear, and if the results of the subquery aren't overwhelming, just execute it on its own and pass the results in: `where_in('App.id', $subquery_results)`. I'd assume `$subquery_results` needs to be an `array`. – svidgen Jul 06 '17 at 13:59
  • @svidgen I know that where_in takes array but the only problem is that single quotes at starting and at end of the `$subquery` by the way thanks for the suggestion. – always-a-learner Jul 07 '17 at 02:58
  • try to use echo $this->get_compiled_select() and see whats the query builded – Mani Kandan Jul 07 '17 at 12:29
  • I have done that I get what is the problem but not get the solution, I think I have to put a bounty on it. – always-a-learner Jul 07 '17 at 12:31
  • Did you tried this one? https://stackoverflow.com/questions/6047149/subquery-in-codeigniter-active-record – mim. Jul 14 '17 at 10:10
  • Yes, But I am keen to use `where_in` @mim. – always-a-learner Jul 14 '17 at 10:24
  • Why don't you grab the results from $subquery and pass the final array into ->where_in? – GeorgeGeorgitsis Jul 14 '17 at 11:49
  • @satafaka sir if you see the [old edit](https://stackoverflow.com/revisions/44926109/1) then you see that i am fetching the data from `App_type` according `app_id` so i use subquey to get that. – always-a-learner Jul 14 '17 at 11:55
  • @satafaka sir i have edited this question many time please see all edits to get what i am doing. – always-a-learner Jul 14 '17 at 11:57
  • the second parameter on the `where_in` should be an `array` and not another query. – sotoz Jul 14 '17 at 13:06
  • 2
    instead of `where_in('App.id',$subquery)` you can try `where("App.id IN (".$subquery.")",NULL, false)` – Atural Jul 14 '17 at 13:15
  • Why 1 down? Can anyone tell me please – always-a-learner Jul 15 '17 at 03:17
  • did you try what i've suggested ? – Atural Jul 17 '17 at 09:15
  • not yet sir, but i will definitely try your suggestion. Thanks @sintakonte – always-a-learner Jul 17 '17 at 10:04
  • $this->db->where() accepts an optional third parameter. If you set it to FALSE, CodeIgniter will not try to protect your field or table names.. That means no quotes and backtick... Also remember Codeigniter also check parameter data type if it is integers no quotes will be add if string..yes there would be single quotes. – Nono Jul 17 '17 at 22:26
  • @sintakonte thanks to you sir your commented suggestion works for me. If you post an answer i will accept it. I have posted my self in case you will note able to answer but if you add an answer then i will remove my answer. please add you answer sir. Thank you very very much. – always-a-learner Jul 21 '17 at 03:29
  • thx dude, i've added an answer – Atural Jul 21 '17 at 07:19

11 Answers11

17

Your task looks pretty simple

instead of

->where_in('App.id',$subquery)  //<-- Here is the problem

you can try the following

->where("App.id IN (".$subquery.")",NULL, false)

You can find this exact information in the Codeigniter Documentation here (point 4 and the section below).

Atural
  • 5,389
  • 5
  • 18
  • 35
6

My approach would be something like below, in a more generic way. I am always trying to follow the MVC pattern while breaking the functionality in small functions. Although you didn't share all of your code, i will suggest it anyway.

You should change my custom given names to functions, arrays etc. so it matches your code. Hope it helps.

Model function

public function getApp_ids($selected_type, $type_count) {
   $subquery = "select app_id FROM App_type WHERE type_id in ($selected_type) group by app_id HAVING COUNT(*) = $type_count";
   $result = $subquery->get();
   if($result->num_rows() > 0) //the check here is relevant to your data
       return $result->result_array();
   return false;
}

Model Function

public function searchApp($appIds, $data) {
  //$appIds and $data are parameters to this function. 
    $search_app_query = $this->db
       ->select('*')
       ->from('App')
       ->join('App_type', 'App_type.app_id = App.id', 'left outer')
       ->join('App_formate', 'App_formate.app_id = App.id', 'left outer')      
       ->where_in('App.id',$appIds)  //pass the array of your IDs
       ->where_in('App_formate.formate_id',$data['selected_formates'])
       ->where('App.ope_min <=',$data['ope_value'])
       ->where('App.ope_max >=',$data['ope_value'])    
       ->group_by("App.id", "desc")
       ->get();

    if($search_app_query->num_rows() > 0) //again, the check is yours
         return $search_app_query->result_array();
    return false;
}

In your Controller, something like this

public function YOUR_FUNCTION($selected_type, $type_count) {
   //call this function from model to grab the app_id you want. Don't forget to pass the parameters you sql needs.
   $appIdsResult = $this->YOUR_MODEL->getApp_ids($selected_type, $type_count);

   //Manipulate your result in another array, so you can get rid off the indexes and do some checks if you want
   $appIds = array();
   foreach ($appIdsResult as $appId) {
       array_push($appIds, $appId['app_id']); //Check the index app_id, it is the result from your DB.
    }

    //Call searchApp from your model and pass the found $appIds and your $data ofcourse
    $result = $this->YOUR_MODEL->searchApp($appIds, $data);
    //In $result will be your answer
}
GeorgeGeorgitsis
  • 1,262
  • 13
  • 29
  • Sir have used subquery because In my search form i am using type, formate and operation from user. at that time as you suggested that i should first get the type and loopite over and then put that in `whare_in` but sir if it is that simple then i would have been given 50 bounty on it. – always-a-learner Jul 14 '17 at 12:33
  • and for `Although you didn't share all of your code` that please see all the edit of mine for this question. It has the table structure and all related information to the process – always-a-learner Jul 14 '17 at 12:35
  • I have specified that i want to just remove that singe quotes. Just that. I am not finding that how can i describe that have used join because it is the best way as what i am doing. @ankitsuthar – always-a-learner Jul 14 '17 at 12:42
  • I suppose that you've tried my solution and didn't work. Sometimes you have to take a step back and rethink what you are trying to do and "transfer" the problem to the next or previous layer. Simplicity with bounty is something irrelevant tho. You can ignore, down vote or just don't accept my answer. Tried to help. Peace. – GeorgeGeorgitsis Jul 14 '17 at 12:42
  • @satafaka I apologize if you feel offended but please understand something that in the question I have added just a problem, this query is the little part of a big project and doing your suggested change will affect the system and takes a too changes in existed code in the system. if you see my edits then you see that I have come so far for this problem. I am just an inch away from the solution that what I think. So your suggested technique and method are obesely good but it didn't work this time. Thanks for the answer sir. – always-a-learner Jul 15 '17 at 03:27
4

replace this code:

->where_in('App.id',$subquery)  //<-- Here is the problem

with this code:

->where_in("App.id", $subquery, FALSE)

the 3rd parameter accept Boolean to determine if the function should escape the value and identifier or not. When set to FALSE, it does not use single quote as escape char.

Hope this helps.

JMS786
  • 1,103
  • 2
  • 11
  • 22
  • @always-a-learner have you tried my solution. I print the query and the single quote is gone.. and you're still in 'where_in' function as you would.. – JMS786 Jul 20 '17 at 03:09
  • 1
    you should include an explanation of what the third argument does, along with a [link to the documentation](https://www.codeigniter.com/userguide3/database/query_builder.html#CI_DB_query_builder::or_where_in) – Ast Derek Jul 20 '17 at 05:37
3

USE MANUAL QUERY ( unsafe ,use very very becareful)

$sql = "SELECT ....[Your Query].....":
$query = $this->db->query($sql);
if ($query->num_rows() > 0){
    // Found
}else{
    // Not Found
}
nui.cmi
  • 41
  • 7
3

//first confirm subquery return only one result if not change in subquery

$subquery = "select GROUP_CONCAT(CONCAT(\"'\",app_id,\"'\")) FROM App_type WHERE type_id in ($selected_type) group by app_id HAVING COUNT(*) = $type_count";

$search_app_query = $this->db
->select('*')
->from('App')
->join('App_type', 'App_type.app_id = App.id', 'left outer')
->join('App_formate', 'App_formate.app_id = App.id', 'left outer')      
->where_in('App.id',$subquery,false)  //<-- pass 3rd parameter as false for removing single quotes
->where_in('App_formate.formate_id',$data['selected_formates'])
->where('App.ope_min <=',$data['ope_value'])
->where('App.ope_max >=',$data['ope_value'])    
->group_by("App.id", "desc")
->get();
Kundan Prasad
  • 556
  • 5
  • 10
1

I think your $subquery was considered as a parameter string, not as a query.
The general syntax of active record method is

->where_in('field_name', array() || 'string values');

You $subquery have to be like this

$subquery = $this->db
        ->select('app_id')
        ->from('App_type')
        ->where_in('type_id',array(3,2,6))
        ->group_by('app_id')
        ->having(' COUNT(*) = 3')
        ->get()
        ->row()
        ->app_id;

Hope it will work :)

Deepak M
  • 849
  • 8
  • 17
  • As i mention in question i get `AND App_formate.formate_id` IN('1', '3')` perfectly as what `where_in` expect so that is not a problem. – always-a-learner Jul 14 '17 at 11:34
  • Your answer is not helping but thanks for the suggestion deepak. if you want to go deeper then you have see what i have edited in question to see the table structure. – always-a-learner Jul 14 '17 at 11:38
1

Instead of

SELECT (*)

use

SELECT *

Instead of

WHERE `App`.`id` IN(
    select app_id FROM App_type
        WHERE type_id in (3,2,6) group by app_id HAVING COUNT(*) = 3)

use

JOIN (
    select app_id FROM App_type
        WHERE type_id in (3,2,6) group by app_id HAVING COUNT(*) = 3
     ) AS x  ON x.app_id = App.id

(Translating into CodeIgniter is left as an exercise to the reader.)

Rick James
  • 135,179
  • 13
  • 127
  • 222
1

First of all after the query, put this code:

echo $this->db->last_query();exit;

This will print the query, and you will have an idea where's the issue. Also copy that query and try to run it in phpmyadmin.

Also try this type of solution as you have single quote issues:

In subquery write $type_count using single quotes i.e '$type_count'

->where("App.ope_min <='",$data['ope_value']."'")
->where("App.ope_max >='",$data['ope_value']."'")    
->group_by("App.id", "desc")
->get();

Let me know if you want to ask something else.

Mobeen Ahmed
  • 121
  • 7
1

Just add a 3rd parameter in where_in statement. Try this -

$subquery = "select app_id FROM app_type WHERE type_id in (3,2,6) group by app_id HAVING COUNT(*) = 3";
    $search_app_query = $this->db
    ->select('*')
    ->from('app')
    ->join('app_type', 'app_type.app_id = app.id', 'left outer')
    ->join('app_formate', 'app_formate.app_id = app.id', 'left outer')      
    ->where_in('app.id',$subquery, FALSE)  
    ->where_in('app_formate.formate_id',array(1,3))
    ->where('app.ope_min <=',3)
    ->where('app.ope_max >=',3)    
    ->group_by("app.id", "desc")
    ->get()->result();
Mahfuzur Rahman
  • 1,497
  • 18
  • 23
1

I would suggest you not to put sub query directly in where in condition because you may also sometimes have zero result. So the best way is to execute your subquery separately like this.

$subdata = $this->db->select("app_id ")->from("App_type ")->where_in("type_id",$selected_type)->group_by(""app_id)->having("COUNT(*) = $type_count")->get()->result_array();

$search_app_query = $this->db
    ->select('*')
    ->from('App')
    ->join('App_type', 'App_type.app_id = App.id', 'left outer')
    ->join('App_formate', 'App_formate.app_id = App.id', 'left outer');
if(!empty($subdata)) {     
    $this->db->where_in('App.id',$subdata);
}
    $this->db->where_in('App_formate.formate_id',$data['selected_formates'])
    ->where('App.ope_min <=',$data['ope_value'])
    ->where('App.ope_max >=',$data['ope_value'])    
    ->group_by("App.id", "desc")
    ->get(); 
0

Thanks To All of you for your suggestions.

I have Find the way to solve my problem without altering my other code.

Thanks to sintakonte-SO user his comment has been the key to solve this problem.

The Solution is just the change of one line code which earlier i want.

$search_app_query = $this->db
    ->select('*')
    ->from('App')
    ->join('App_type', 'App_type.app_id = App.id', 'left outer')
    ->join('App_formate', 'App_formate.app_id = App.id', 'left outer') 

    // This is what he suggested me to change and it works. 
    ->where('App.id IN('.$subquery.')')     

    ->where_in('App_formate.formate_id',$data['selected_formates'])
    ->where('App.ope_min <=',$data['ope_value'])
    ->where('App.ope_max >=',$data['ope_value'])    
    ->group_by("App.id", "desc")
    ->get();

Many thanks to sintakonte-SO user again.

always-a-learner
  • 3,671
  • 10
  • 41
  • 81