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
REPLACE($subquery, '''', '')
->where_in('App.id',trim($subquery,"'"))
$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.
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).
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
}
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.
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
}
//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();
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 :)
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.)
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.
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();
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();
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.
Related
I am trying to execute a self join query in Laravel. I am getting while i try to execute the same as raw query
$data['d_meetings'] =DB::select("select t1.*,t2.* from `leads_followup_details` as `t1` inner join `leads_followup_details` as `t2` on `t1`.`leads_enquiry_details_enquiry_id` = `t2`.`leads_enquiry_details_enquiry_id` inner join `leads_enquiry_details` on `enquiry_id` = `t1`.`leads_enquiry_details_enquiry_id` where `t1`.`followup_meeting` = 'direct' and t1.followup_id<t2.followup_id and t1.followup_next_followup_date=t2.followup_date and `t2`.`followup_current_meeting` = 'direct' and `enquiry_deleted` = 1 group by `t1`.`followup_id`");
$data['d_meetings'] = DB::table('leads_followup_details as t1')
->join('leads_followup_details as t2', 't1.leads_enquiry_details_enquiry_id', 't2.leads_enquiry_details_enquiry_id')
->where('t2.followup_id', '>', 't1.followup_id')
->where('t2.followup_id', '!=', 't1.followup_id')
->whereDate('t1.followup_next_followup_date', '=', 't2.followup_date')
->where('t1.followup_meeting', 'direct')
->join('leads_enquiry_details', 'enquiry_id', 't1.leads_enquiry_details_enquiry_id')->where('enquiry_deleted', 1)
->groupBy('t1.followup_id')->get();
but this is not working as my expectation .
Please help
You can try:
$data['d_meetings'] = DB::table('leads_followup_details as t1')
->select('t1.followup_id', 't2.followup_id', 't1.followup_next_followup_date', 't2.followup_date', 't2.followup_current_meeting', 't1.followup_meeting')
->join('leads_followup_details as t2','t1.leads_enquiry_details_enquiry_id','t2.leads_enquiry_details_enquiry_id')
->join('leads_enquiry_details','enquiry_id','t1.leads_enquiry_details_enquiry_id')
->where('t1.followup_id','<','t2.followup_id')
->where('t1.followup_id','<>','t2.followup_id')
->where('t1.followup_next_followup_date','=','t2.followup_date')
->where('t1.followup_meeting', 'direct')
->where('t2.followup_current_meeting', 'direct')
->where('enquiry_deleted',1)
->groupBy('t1.followup_id')->get();
I see you miss t2.followup_current_meeting ='direct'
It seems that your ->whereDate('t2.followup_date','=','t2.followup_next_followup_date')
doesn't match your SQL and t1.followup_next_followup_date=t2.followup_date
It might be easier if you write out the Laravel query in the same order as the SQL (and observe the re-added ->where('t2.followup_current_meeting', 'direct')):
$data['d_meetings'] = DB::table('leads_followup_details as t1')
->join('leads_followup_details as t2',
't1.leads_enquiry_details_enquiry_id',
't2.leads_enquiry_details_enquiry_id')
->join('leads_enquiry_details','enquiry_id',
't1.leads_enquiry_details_enquiry_id')
->where('t1.followup_id','<>','t2.followup_id')
->where('t1.followup_id','<','t2.followup_id')
->where('t1.followup_meeting', 'direct')
->where('t2.followup_current_meeting', 'direct')
->whereDate('t1.followup_next_followup_date','=',
't2.followup_date')
->where('enquiry_deleted',1)
->groupBy('t1.followup_id')->get();
I have a query to select data from multiple tables. How do I write its equivalent code in codeigniter.
See the query:
select *
from A inner join B on (A.ad_no=B.ad_no)
where B.ad_no in (select ad_no
from A
where $staff!='00:00' and $staff!='0:00')
order by B.ctype asc, B.cname asc,B.ad_no asc
I tried a query in codeigniter but its taking longer time to load the result.
You can try the following (i removed the $ sign from staff)
$query = $this->db
->select("*")
->from("A")
->join("B", "A.ad = B.ad_no")
->where("B.ad_no in (select ad_no from A where staff!='00:00' and staff!='0:00')",NULL, false)
->order_by("B.ctype", "ASC")
->order_by("B.cname", "ASC")
->order_by("B.ad_no", "ASC")
->get();
You get a generated output with the following statement
echo $this->db
->select("*")
->from("A")
->join("B", "A.ad = B.ad_no")
->where("B.ad_no in (select ad_no from A where staff!='00:00' and staff!='0:00')",NULL, false)
->order_by("B.ctype", "ASC")
->order_by("B.cname", "ASC")
->order_by("B.ad_no", "ASC")
->get_compiled_select();
get subquery library from https://github.com/NTICompass/CodeIgniter-Subqueries/edit/master/libraries/Subquery.php
try the following code
$this->db->select('*')->from('A');
$this->db->join('b','A.ad_no=B.ad_no','inner');
$sub = $this->subquery->start_subquery('where_in');
$sub->select('ad_no')->from('A')->where("staff!='00:00'")->where("staff!='0:00'");
$this->subquery->end_subquery('B.ad_no', TRUE);
$this->db->order_by('B.ctype','asc');
$this->db->order_by('B.cname','asc');
$this->db->order_by('B.ad_no','asc');
$query=$this->db->get();
I am trying to make the following query in laravel:
SELECT a.name AS subname, a.area_id, b.name, u. id, u.lawyer_id,u.active_search,
FROM subarea a
LEFT JOIN user_subarea u ON u.subarea_id = a.id
AND u.user_id = ?
LEFT JOIN branch b ON a.area_id = b.id
The idea is to obtain the subareas and see if the search is activated by the user.
The user_subarea table might have a record that matches the id of the subarea table where the active_search is equal to 0 or 1. If it doesn't exist I would like the query to return null.
While I was able to achieve this in raw SQL when I try the same with eloquent in Laravel I am not returning any value. I have done the following:
$query = DB::table('subarea')
->join('user_subarea', function($join)
{
$value = \Auth::user()->id;
$join->on( 'subarea.id', '=', 'user_subarea.subarea_id')->where('user_subarea.user_id', '=',$value);
})
->leftJoin('branch', 'subarea.area_id', '=', 'branch.id')
->select('branch.name', 'subarea.name as subarea', 'user_subarea.active_search_lawyer', 'user_subarea.id' )
->get();
Any help will be much appreciated.
I found by myself the answer it was just to add a lefjoin in the first join. It is not in the laravel docs but works too.
$query = DB::table('subarea')
->lefjoin('user_subarea', function($join)
{
$value = \Auth::user()->id;
$join->on( 'subarea.id', '=', 'user_subarea.subarea_id')->where('user_subarea.user_id', '=',$value);
})
->leftJoin('branch', 'subarea.area_id', '=', 'branch.id')
->select('branch.name', 'subarea.name as subarea', 'user_subarea.active_search_lawyer', 'user_subarea.id' )
->get();
Try this one, If you get a problem, please comment.
$value = \Auth::user()->id;
$query = DB::table('subarea')
->where('user_subarea.user_id', '=',$value)
->leftJoin('user_subarea', 'subarea.id', '=', 'user_subarea.subarea_id')
->leftJoin('branch', 'subarea.area_id', '=', 'branch.id')
->select('subarea.name AS subname','subarea.area_id', 'branch.name', 'user_subarea.id','user_subarea.lawyer_id','user_subarea.active_search')
->get();
I would like to generate following query using yii2:
SELECT COUNT(*) AS cnt FROM lead WHERE approved = 1 GROUP BY promoter_location_id, lead_type_id
I have tried:
$leadsCount = Lead::find()
->where('approved = 1')
->groupBy(['promoter_location_id', 'lead_type_id'])
->count();
Which generates this query:
SELECT COUNT(*) FROM (SELECT * FROM `lead` WHERE approved = 1 GROUP BY `promoter_location_id`, `lead_type_id`) `c`
In yii 1.x I would've done the following:
$criteria = new CDbCriteria();
$criteria->select = 'COUNT(*) AS cnt';
$criteria->group = array('promoter_location_id', 'lead_type_id');
Thanks!
Solution:
$leadsCount = Lead::find()
->select(['COUNT(*) AS cnt'])
->where('approved = 1')
->groupBy(['promoter_location_id', 'lead_type_id'])
->all();
and add public $cnt to the model, in my case Lead.
As Kshitiz also stated, you could also just use yii\db\Query::createCommand().
You can get the count by using count() in the select Query
$leadCount = Lead::find()
->where(['approved'=>'1'])
->groupBy(['promoter_location_id', 'lead_type_id'])
->count();
Reference Link for various functions of select query
If you are just interested in the count, use yii\db\Query as mentioned by others. Won't require any changes to your model:
$leadsCount = (new yii\db\Query())
->from('lead')
->where('approved = 1')
->groupBy(['promoter_location_id', 'lead_type_id'])
->count();
Here's a link to the Yii2 API documentation
Without adding the $cnt property to model
$leadsCount = Lead::find()
->select(['promoter_location_id', 'lead_type_id','COUNT(*) AS cnt'])
->where('approved = 1')
->groupBy(['promoter_location_id', 'lead_type_id'])
->createCommand()->queryAll();
Just a note, in case it helps anyone, that a getter used as a property is countable (whereas if called as a function it will return 1). In this example, I have a Category class with Listings joined by listing_to_category. To get Active, Approved Listings for the Category, I return an ActiveQuery, thus:
/**
* #return \yii\db\ActiveQuery
*/
public function getListingsApprovedActive() {
return $this->hasMany(Listing::className(), ['listing_id' => 'listing_id'])
->viaTable('listing_to_category', ['category_id' => 'category_id'])
->andWhere(['active' => 1])->andWhere(['approved' => 1]);
}
Calling count on the property of the Category will return the record count:
count($oCat->listingsApprovedActive)
Calling count on the function will return 1:
count($oCat->getListingsApprovedActive())
I need a query like this
SELECT * FROM (`users`)
LEFT JOIN `users_phone_numbers`
ON `users`.`id`= `users_phone_numbers`.`user_id`
LEFT JOIN `phone_number`
ON (`phone_number`.`id`= `users_phone_numbers`.`phone_num_id` AND users_phone_numbers.is_active = 1)
WHERE `users`.`id` = 56
i have code like this in codeigniter
$this->db->select('*');
$this->db->from('users');
$this->db->join('users_phone_numbers',
'users.id= users_phone_numbers.user_id',
'left');
$this->db->join('phone_number',
'(phone_number.id= users_phone_numbers.phone_num_id AND users_phone_numbers.is_active = 1)',
'left');
$this->db->where('users.id = '. $id);
$result = $q->result_array();
But i got this error
If you check Codeigniter's handling of the condition function, you will see the following:
// Strip apart the condition and protect the identifiers
if (preg_match('/([\w\.]+)([\W\s]+)(.+)/', $cond, $match))
Codeigniter is stripping the opening bracket from the query. Can you not move the LEFT JOIN additional clause within the WHERE clause to get around this?
EDIT:
$this->db->select('*');
$this->db->from('users');
$this->db->join('users_phone_numbers',
'users.id= users_phone_numbers.user_id',
'left');
$this->db->join('phone_number',
'phone_number.id= users_phone_numbers.phone_num_id)',
'left');
$this->db->where(array('users.id => '. $id, 'users_phone_numbers.is_active' => 1));
$result = $q->result_array();
You need to remove the second condition of the join.
$this->db->join('phone_number',
'phone_number.id= users_phone_numbers.phone_num_id AND users_phone_numbers.is_active = 1',
'left');
remove brackets like above. it works for me when there is no bracket