Laravel Query Builder "select" strange behaviour - php

I have a problem with the following code:
public function index() {
$qObj = \DB::table('customers as c')
->join('companies_has_customers as chc', 'chc.comhc_cus_id', '=', 'c.cus_id')
->join('cuscategory as cc', 'chc.comhc_cca_id', '=', 'cc.cca_id')
->join('transactions as t','t.trn_cus_id', '=','c.cus_id')
->select('t.trn_id');
$qObj->where('comhc_com_id', '=', $this->companyId);
$res = array(
'count' => $qObj->count(),
'items' => $qObj->get()
);
//print_r($this->showLastQuery());
return parent::prepareResponse($res, 200, 'customers');
}
And this piece of code produces following SQL query:
select * from `customers` as `c`
inner join `companies_has_customers` as `chc` on `chc`.`comhc_cus_id` = `c`.`cus_id`
inner join `cuscategory` as `cc` on `chc`.`comhc_cca_id` = `cc`.`cca_id`
inner join `transactions` as `t` on `t`.`trn_cus_id` = `c`.`cus_id`
where comhc_com_id` = 1
QUESTION:
Why QueryBuilder produce select *... instead of select t.trn_id... as is requested in above syntax?

Change the order:
$res = array(
'items' => $qObj->get(),
'count' => $qObj->count()
);
and it will work.
But better, instead of querying DB twice, do this:
$items = $qObj->get();
$res = array(
'items' => $items,
'count' => count($items)
);
The problem with your code is count() method behaviour - it resets the columns property (set with select), that's all.

Put it in $qObj->get(['t.trn_id']) like this:
$res = array(
'items' => $items = $qObj->get(['t.trn_id']),
'count' => count($items) // count the cached $items
);
Instead of select ( Remove select('t.trn_id')).

Related

how to search using the sum of case when in cakephp

I want to do implement a search in the generated data of the sum count of a case when in cakephp with or or conditions in each data.
SELECT `Branches`.`name` AS `Branches__name` , `Branches`.`code` AS `Branches__code` , (
COUNT(
CASE WHEN `prodCarried`.`carried` =1
THEN 1
END )
) AS `carried` , (
COUNT(
CASE WHEN `prodCarried`.`carried` =0
THEN 1
END )
) AS `unCarried`
FROM `branches` `Branches`
INNER JOIN `products_carried_per_branches` `prodCarried` ON ( prodCarried.company_id = Branches.company_id
AND prodCarried.branch_code = Branches.code )
WHERE (
`Branches`.`company_id` =200017
AND `Branches`.`deleted` =0
AND `prodCarried`.`deleted` =0
)
GROUP BY `code`
HAVING COUNT(
CASE WHEN `prodCarried`.`carried` =1
THEN 1
END ) =39
the picture shows the mysql result without the having code
while this is my cakephp code, I want to implement the having sql into cakephp or condition to search the generated sum count or search the data name and code. is this possible or nah
$carriedCase = $query->newExpr()
->addCase(
$query->newExpr()->add(['prodCarried.carried' => '1']),
1,
'integer'
);
$unCarriedCase = $query->newExpr()
->addCase(
$query->newExpr()->add(['prodCarried.carried' => '0']),
1,
'integer'
);
//disctinct code
$query ->select([
'name',
'code',
'carried' => $query->func()->count($carriedCase),
'unCarried' => $query->func()->count($unCarriedCase),
'prodCarried.id',
'prodCarried.validity_start',
'prodCarried.validity_end',
]);
$query ->distinct([
'code'
]);
$query->join([
'prodCarried' => [
'table' =>'products_carried_per_branches',
'type' => 'inner',
'conditions' => [
'prodCarried.company_id = Branches.company_id',
'prodCarried.branch_code = Branches.code',
]
]
]);
$query->where(function (QueryExpression $exp, Query $q) use($option,$search){
$exp->eq('Branches.company_id', $option['company_id']);
$exp->eq('Branches.deleted', 0);
$exp->eq('prodCarried.deleted', 0);
if(!empty($search)){
$orConditions = $exp->or_(function (QueryExpression $or) use ($search) {
$or->like('name', "%$search%");
$or->like('code', "%$search%");
//****************************
return $or;
});
$exp->add($orConditions);
}
return $exp;
});
Depending on your DBMS you can refer to the aggregate of the select list:
$query->having([
'carried' => $searchCount,
]);
Otherwise you have to recreate the aggregate:
$query->having(
function (
\Cake\Database\Expression\QueryExpression $exp,
\Cake\ORM\Query $query
) use (
$carriedCase,
$searchCount
) {
return $exp->eq(
$query->func()->count($carriedCase),
$searchCount
);
}
);
See also
Cookbook > Database Access & ORM > Query Builder > Aggregates - Group and Having

Is it Possible to do a datatable search using the generated sumcount of the sum case in CAKEPHP [duplicate]

I want to do implement a search in the generated data of the sum count of a case when in cakephp with or or conditions in each data.
SELECT `Branches`.`name` AS `Branches__name` , `Branches`.`code` AS `Branches__code` , (
COUNT(
CASE WHEN `prodCarried`.`carried` =1
THEN 1
END )
) AS `carried` , (
COUNT(
CASE WHEN `prodCarried`.`carried` =0
THEN 1
END )
) AS `unCarried`
FROM `branches` `Branches`
INNER JOIN `products_carried_per_branches` `prodCarried` ON ( prodCarried.company_id = Branches.company_id
AND prodCarried.branch_code = Branches.code )
WHERE (
`Branches`.`company_id` =200017
AND `Branches`.`deleted` =0
AND `prodCarried`.`deleted` =0
)
GROUP BY `code`
HAVING COUNT(
CASE WHEN `prodCarried`.`carried` =1
THEN 1
END ) =39
the picture shows the mysql result without the having code
while this is my cakephp code, I want to implement the having sql into cakephp or condition to search the generated sum count or search the data name and code. is this possible or nah
$carriedCase = $query->newExpr()
->addCase(
$query->newExpr()->add(['prodCarried.carried' => '1']),
1,
'integer'
);
$unCarriedCase = $query->newExpr()
->addCase(
$query->newExpr()->add(['prodCarried.carried' => '0']),
1,
'integer'
);
//disctinct code
$query ->select([
'name',
'code',
'carried' => $query->func()->count($carriedCase),
'unCarried' => $query->func()->count($unCarriedCase),
'prodCarried.id',
'prodCarried.validity_start',
'prodCarried.validity_end',
]);
$query ->distinct([
'code'
]);
$query->join([
'prodCarried' => [
'table' =>'products_carried_per_branches',
'type' => 'inner',
'conditions' => [
'prodCarried.company_id = Branches.company_id',
'prodCarried.branch_code = Branches.code',
]
]
]);
$query->where(function (QueryExpression $exp, Query $q) use($option,$search){
$exp->eq('Branches.company_id', $option['company_id']);
$exp->eq('Branches.deleted', 0);
$exp->eq('prodCarried.deleted', 0);
if(!empty($search)){
$orConditions = $exp->or_(function (QueryExpression $or) use ($search) {
$or->like('name', "%$search%");
$or->like('code', "%$search%");
//****************************
return $or;
});
$exp->add($orConditions);
}
return $exp;
});
Depending on your DBMS you can refer to the aggregate of the select list:
$query->having([
'carried' => $searchCount,
]);
Otherwise you have to recreate the aggregate:
$query->having(
function (
\Cake\Database\Expression\QueryExpression $exp,
\Cake\ORM\Query $query
) use (
$carriedCase,
$searchCount
) {
return $exp->eq(
$query->func()->count($carriedCase),
$searchCount
);
}
);
See also
Cookbook > Database Access & ORM > Query Builder > Aggregates - Group and Having

CakePHP 3.6: Count distinct records from table

I am trying to achieve a distinct count on a table with a where condition.
This is what I have tried:
$customerServiceTypes = TableRegistry::get('CustomerServiceTypes');
$customers_count = $customerServiceTypes->find('all', array(
'fields' => 'DISTINCT CustomerServiceType.customer_id',
'conditions' => array("CustomerServiceTypes.service_type_id" => $id)))->count();
But its not working. I get 25 as result but it should be 2. Distinct is not working.
$customerServiceTypes = TableRegistry::get('CustomerServiceTypes');
$customers_count = $customerServiceTypes->find()
->select(['customer_id'])
->distinct()
->where(['service_type_id =' => $id])->count();

Codeigniter Join messing up 'id' field

I have a codeigniter query to get a list of questions from my database. I'm using some joins to get the category name and the answer type. Its working good to output everything, but when i try and output the id of the row from the "questions" table, it displays as "2" which is the answer_type_id.
Maybe I'm doing this wrong, i'm fairly new to joins. Any help is appreciated:
function get_questions($category_id) {
$this->db->select('*');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id');
$this->db->order_by('priority', 'desc');
$query = $this->db->get();
$data = array();
foreach ($query->result() as $row) {
$data[] = array(
'id' => $row->id,
'category' => $row->category,
'type' => $row->type,
'question' => $row->question,
'answer' => $row->answer_type,
'priority' => $row->priority,
);
}
return $data;
}
Update===============
I have added "left" for my join type but the problem persists. The question id's should be 2 and 3. But when i print my array returned, they are both 2 (which is the answer_type_id).
Here is the updated code (only left join changed)...
function get_questions($category_id) {
$this->db->select('*');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id', 'left');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id', 'left');
$this->db->order_by('priority', 'desc');
$query = $this->db->get();
$data = array();
foreach ($query->result() as $row) {
$data[] = array(
'id' => $row->id,
'category' => $row->category,
'type' => $row->type,
'question' => $row->question,
'answer' => $row->answer_type,
'priority' => $row->priority,
);
}
return $data;
}
And here is the output it returns:
Array (
[0] => Array (
[id] => 2
[category] => Herbs
[type] => 2
[question] => What Type of Vehicle do You own?
[answer] => Drop down list [priority] => 0
)
[1] => Array (
[id] => 2
[category] => Herbs
[type] => 3
[question] => What is Your Favorite Herb
[answer] => Drop down list [priority] => 0
)
)
The reason you are not getting the proper ids is you are selecting *.
Use aliases so that give them separate names and you will be access them
as you want like this.
function get_questions($category_id) {
$this->db->select('questions.*');
$this->db->select('answer_type.answer_type_id');
$this->db->select('answer_type.other_column');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id', 'left');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id', 'left');
$this->db->order_by('priority', 'desc');
return $this->db->get()->result_array();
}
Also Codeigniter database class provide a method call result_array()
Which is already alternate of the loop you are using. So use it instead of
extra loop code.
Just change it to this:
'id' => $row->category_id
The problem is that the id column is ambiguous. In cases where your selecting columns across tables with columns that have the same name, you can also use the AS keyword to rename a column.
For example:
$this->db->select("questions.*, categories.id AS cat_id, answer_type.id AS ans_id");
By chance are you (maybe) only getting one row as a result, where all the ids match?
You should specify your join type, or be more specific in your query, so that you keep the question.id value.
For this question, you could specify the join as a left join, to keep all the data from questions table and tack on from categories and answer_types where its found.
see CodeIgniter ActiveRecord docs
The questions id needs to be defined as its own name. To pull ALL the data from the other tables, follow up with asterisks for the other tables, like so...
function get_questions($category_id) {
$this->db->select('questions.id as questions_id, questions.*, categories.*, answer_type.*');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id', 'left');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id', 'left');
$this->db->order_by('priority', 'desc');
$query = $this->db->get();
$data = array();
foreach ($query->result() as $row) {
$data[] = array(
'id' => $row->questions_id,
'category' => $row->category,
'type' => $row->type,
'question' => $row->question,
'answer' => $row->answer_type,
'priority' => $row->priority,
);
}
return $data;
}
Use alias for your id columns like the above example.
...
$this->db->select("questions.*, categories.id AS cat_id, answer_type.id AS ans_id");
...
...
Now you get your data because only have one id column.
Here you have an article: http://chrissilich.com/blog/codeigniter-active-record-aliasing-column-names-to-prevent-overwriting-especially-columns-named-id/

Codeigniter Active Record: is it possible to remove the brakets around the table name

I am using codeigniter to produce a left join of two tables, but need to remove the brackets that active record applies to the table name. you know SELECT blah FROM ('some table') I really need these brackets to disappear.
here is my input array:
$retrieve_arr = array(
'table' => 'entries',
'select' => array('entries.entry_id', 'entries.score', 'sc_users.name', 'clients.name'),
'joins' => array(
'clients' => 'entries.client_id = clients.client_id',
'sc_users' => 'entries.sc_user_id = sc_users.sc_user_id'
),
'joinType' => 'left',
'where' => 'null'
);
here is my model:
$retrieve = new Data();
if($get_arr['select'] != 'null')
{
$query = $retrieve->db->select($get_arr['select']);
}
foreach($get_arr['joins'] as $additional => $value)
{
$retrieve->db->join($additional, $value, $get_arr['joinType']);
}
if($get_arr['where'] != 'null')
{
foreach ($get_arr['where'] as $name => $value)
{
$retrieve->db->where($name, $value);
}
}
$query = $retrieve->db->get($get_arr['table']);
$queryData = $query->result_array();
return $queryData;
and here is what my query string:
SELECT `entries`.`entry_id`, `entries`.`score`, `sc_users`.`name`, `clients`.`name` FROM (`entries`) LEFT JOIN `sc_users` ON `entries`.`sc_user_id` = `sc_users`.`sc_user_id` LEFT JOIN `clients` ON `sc_users`.`client_id` = `clients`.`client_id`Array
I have been looking for this for a while so your help is very much appreciated.
If you are referring to the ` backticks, in the Select() portion, use a FALSE as the second parameter (refer to the Users Guide for more info)

Categories