how to write mysql AND/OR in cakephp find() method [duplicate] - mysql

This question already has answers here:
cakephp OR condition
(4 answers)
Closed 6 years ago.
I wanted to find out a way to write the following code into cakephp find() method but the didn't find related resource on the cakebook.
my code is
SELECT * FROM Customers
WHERE
(Country='Germany' AND City='München')
OR (Country='Germany' AND CustomerName='München');
please share a way to write this accordingly in find() method. Thanks

You can do this using the OR key when using where:
$query = $this->Customers
->find()
->where([
'OR' => [
[
'City' => 'München',
'Country' => 'Germany'
],
[
'Country' => 'Germany',
'CustomerName' => 'München'
]
]
]);
This could be simplified to:
$query = $this->Customers
->find()
->where([
'Country' => 'Germany',
'OR' => [
['City' => 'München'],
['CustomerName' => 'München']
]
]);
See http://book.cakephp.org/3.0/en/orm/query-builder.html#advanced-conditions, I find using the andWhere and orWhere functions in combination so just stick to where!

Try
$query = $this->Customers->find(
'all',
[
'conditions' => [
'Country' => 'Germany',
'OR' => [
[
'City' => 'München',
],
[
'CustomerName' => 'München'
]
]
]
]
);
In the cookbook it says to wrap the or conditions in arrays if they are pertaining to the same field http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#complex-find-conditions

If you want to paginate results you can try this:
public function yourFunctionName() {
$this->paginate['conditions']['and'][] = ['Country' => 'Germany'];
$this->paginate['conditions']['and']['or'][] = ['City' => 'München'];
$this->paginate['conditions']['and']['or'][] = ['CustomerName' => 'München'];
$customers = $this->paginate($this->Customers);
$this->set(compact('customers'));
$this->set('_serialize', ['customers']);
}

Related

Yii2 - QueryAll is having issue

I am using Query Builder with multiple where clause. When I use this query,
$query1 = new \yii\db\Query();
$query1->select('*')
->from('assessment_score ca')
->where(['AND','ca.is_status' => 0, 'ca.assessment_type' => 'CONTINUOUS ASSESSMENT', 'ca.ca_type' => 'CONTINUOUS ASSESSMENT'])
->andFilterWhere(['ca.state_office_id' => $model->report_state_office_id])
->andFilterWhere(['ca.study_centre_id' => $model->report_study_centre_id])
->andFilterWhere(['ca.programme_id' => $model->report_programme_id])
->andFilterWhere(['ca.department_id' => $model->report_department_id])
->andFilterWhere(['ca.academic_level_id' => $model->report_academic_level_id])
->andFilterWhere(['ca.academic_year_id' => $model->report_academic_year_id])
->andFilterWhere(['ca.academic_semester_id' => $model->report_academic_semester_id])
->andFilterWhere(['ca.course_id' => $model->report_course_id]);
$command=$query1->createCommand();
$ca_data=$command->queryAll();
I got this error
Then, when I changed the code to this, no response:
$selected_list = $_POST['ca'];
$query1 = new \yii\db\Query();
$query1->select('*')
->from('assessment_score ca')
->where(['ca.is_status' => 0])
->andWhere(['ca.assessment_type' => 'CONTINUOUS ASSESSMENT'])
->andWhere(['ca.ca_type' => 'CONTINUOUS ASSESSMENT'])
->andFilterWhere(['ca.state_office_id' => $model->report_state_office_id])
->andFilterWhere(['ca.study_centre_id' => $model->report_study_centre_id])
->andFilterWhere(['ca.programme_id' => $model->report_programme_id])
->andFilterWhere(['ca.department_id' => $model->report_department_id])
->andFilterWhere(['ca.academic_level_id' => $model->report_academic_level_id])
->andFilterWhere(['ca.academic_year_id' => $model->report_academic_year_id])
->andFilterWhere(['ca.academic_semester_id' => $model->report_academic_semester_id])
->andFilterWhere(['ca.course_id' => $model->report_course_id]);
$command=$query1->createCommand();
$ca_data=$command->queryAll();
How do I re-write the code appropriately to solve the issue of multiple where clause?
You might need to change the query format for the where() statement as you need to provide every condition (name=>value pair) as a separate array rather than just name=>value pairs, you currently have
->where(['AND', 'ca.is_status' => 0, 'ca.assessment_type' => 'CONTINUOUS ASSESSMENT', 'ca.ca_type' => 'CONTINUOUS ASSESSMENT'])
which will create the query like below if no other parameter is provided for andFilterWhere() statements.
SELECT * FROM `assessment_score` `ca`
WHERE (0)
AND (CONTINUOUS ASSESSMENT) AND (CONTINUOUS ASSESSMENT)
which is incorrect and throwing the error, you can notice that in your Exception image, so change it to the one below
->where(['AND',
['ca.is_status' => 0],
['ca.assessment_type' => 'CONTINUOUS ASSESSMENT'],
['ca.ca_type' => 'CONTINUOUS ASSESSMENT']
])
which will output the query like
SELECT * FROM `assessment_score` `ca`
WHERE (`ca`.`is_status`=0)
AND (`ca`.`assessment_type`='CONTINUOUS ASSESSMENT')
AND (`ca`.`ca_type`='CONTINUOUS ASSESSMENT')
Your complete query should look like this
$query1 = new \yii\db\Query();
$query1->select('*')
->from('assessment_score ca')
->where(['AND',
['ca.is_status' => 0],
['ca.assessment_type' => 'CONTINUOUS ASSESSMENT'],
['ca.ca_type' => 'CONTINUOUS ASSESSMENT']
])
->andFilterWhere(['ca.state_office_id' => $model->report_state_office_id])
->andFilterWhere(['ca.study_centre_id' => $model->report_study_centre_id])
->andFilterWhere(['ca.programme_id' => $model->report_programme_id])
->andFilterWhere(['ca.department_id' => $model->report_department_id])
->andFilterWhere(['ca.academic_level_id' => $model->report_academic_level_id])
->andFilterWhere(['ca.academic_year_id' => $model->report_academic_year_id])
->andFilterWhere(['ca.academic_semester_id' => $model->report_academic_semester_id])
->andFilterWhere(['ca.course_id' => $model->report_course_id]);
$command = $query1->createCommand();
$ca_data = $command->queryAll();
based on yii2 guide for Operator Format
Operator format allows you to specify arbitrary conditions in a
programmatic way. It takes the following format:
[operator, operand1, operand2, ...] where the operands can each be
specified in string format, hash format or operator format
recursively, while the operator can be one of the following:
and: the operands should be concatenated together using AND. For
example, ['and', 'id=1', 'id=2']
so in your case should be
->where(['AND', 'ca.is_status = 0',
"ca.assessment_type = 'CONTINUOUS ASSESSMENT'",
"ca.ca_type = 'CONTINUOUS ASSESSMENT'"])
https://www.yiiframework.com/doc/guide/2.0/en/db-query-builder#operator-format
All you need is to remove AND from array passed to where():
->where([
'ca.is_status' => 0,
'ca.assessment_type' => 'CONTINUOUS ASSESSMENT',
'ca.ca_type' => 'CONTINUOUS ASSESSMENT'
])
If you pass associative array, it will be treated as pairs of column-value for conditions for WHERE in query. If you pass AND as first element, it is no longer a associative array, and query builder will ignore keys and only combine values as complete condition.

CakePHP 3 quoting function names defined in 'fields' configuration of my find() call

I am querying a database table conveniently named order and because of that I had to set 'quoteIdentifiers' => true in my app.php configuration. However, when I'm putting function names into the fields configuration of my find() call, CakePHP quotes them too.
$orders->find('all', array(
'fields' => array(
'DATE(Orders.date_added)',
'COUNT(*)',
),
'conditions' => array(
'Orders.order_status_id <>' => 0,
),
'group' => array(
'DATE(Orders.date_added)',
),
));
The query above ends up calling
SELECT <...>, `DATE(Orders.date_added)` FROM `order` <...>
which obviously throws an error.
I googled a lot, tried this:
$orders = $orders->find('all', array(
'conditions' => array(
'Orders.order_status_id <>' => 0,
),
'group' => array(
'DATE(Orders.date_added)',
),
))->select(function($exp) {
return $exp->count('*');
});
and that didn't work either, throwing me some array_combine error.
Is there any way for me to un-quote those function names, while keeping the rest of the query quoted automatically? Here's what I'm trying to accomplish:
SELECT <...>, DATE(Orders.date_added) FROM `order` <...>
Please help.
You should use function expressions, they will not be quoted, except for arguments that are explicitly being defined as identifiers:
$query = $orders->find();
$query
->select([
'date' => $query->func()->DATE([
'Orders.date_added' => 'identifier'
]),
'count' => $query->func()->count('*')
])
->where([
'Orders.order_status_id <>' => 0
])
->group([
$query->func()->DATE([
'Orders.date_added' => 'identifier'
])
]);
I'd generally suggest that you use expressions instead of passing raw SQL snippets wherever possible, it makes generating SQL more flexible, and more cross-schema compatible.
See also
Cookbook > Database Access & ORM > Query Builder > Using SQL Functions

Yii2 update with multiple conditions

$this->localdb->createCommand()
->update(
$this->MYTable,
[
'name' => $el['new'],
'data' => $el['data'],
],
[
'userId', $this->user,
'product_id', $this->productId,
'name', $el['old'],
'created', $el['date'],
'category', $el['cat'],
]
);
I tried to use the following command to update a row using multiple where conditions, but it doesn't work for some reason. The documentation doesn't seem to cover this case and doesn't seem to be updated, because the update() method seems to match the updateAll method instead of the update method for some reason (maybe it was updated?). So I was wondering what was the correct way to do this.
You have a syntax error. Try following:
$this->localdb->createCommand()
->update(
$this->MYTable,
[
'name' => $el['new'],
'data' => $el['data'],
],
[
'userId' => $this->user,
'product_id' => $this->productId,
'name' => $el['old'],
'created' => $el['date'],
'category' => $el['cat'],
]
);
Try This updateAll query :
MYTable::updateAll([ // field to be updated in first array
'name' => $el['new'],
'data' => $el['data']
],
[ // conditions in second array
'userId' => $this->user,
'product_id' => $this->productId,
'name' => $el['old'],
'created' => $el['date'],
'category' => $el['cat']
]);

CakePHP 3 CounterCache not updating on delete with belongsToMany SelfJoinTable

CakePHP vertion: 3.3.11
CounterCache working on add method but not working on delete method.
SentenceTable
$this->belongsToMany('Sentences', [
'foreignKey' => 'second_sentence_id',
'targetForeignKey' => 'sentence_id',
'joinTable' => 'sentences_sentences'
]);
$this->belongsToMany('SecondSentences', [
'className' => 'Sentences',
'foreignKey' => 'sentence_id',
'targetForeignKey' => 'second_sentence_id',
'joinTable' => 'sentences_sentences'
]);
SentencesSentencesTable
$this->belongsTo('Sentences', [
'foreignKey' => 'sentence_id',
'joinType' => 'INNER'
]);
$this->belongsTo('SecondSentences', [
'className'=>'Sentences',
'foreignKey' => 'second_sentence_id',
'joinType' => 'INNER'
]);
$this->addBehavior('CounterCache', ['Sentences' => ['ver_count']]);
SentencesController Add method updating ver_count
$sentence = $this->Sentences->get($this->request->data['id']);
$sentence = $this->Sentences->patchEntity($sentence, $this->request->data);
$this->Sentences->SecondSentences->saveStrategy('append');
$this->Sentences->save($sentence);
SentencesController delete method not updating ver_count
$sentence = $this->Sentences->SecondSentences->get($this->request->data['id'],['contain'=>['Sentences']]);
if ($sentence->user_id == $this->Auth->user('id')) {
$this->Sentences->SecondSentences->delete($sentence);
$sentences = $this->Sentences->get($sentence->sentences[0]->id,['contain'=>['SecondSentences']]);
// NOW I AM USING BELOW CODE FOR UPDATING VER_COUNT.
$this->Sentences->updateAll(['ver_count'=>count($sentences->second_sentences)], ['id'=>$sentence->sentences[0]->id]);
}
How are your records deleted. Just as mentioned in cakephp documentation (CounterCache):
The counter will not be updated when you use deleteAll(), or execute SQL you have written.
And:
The CounterCache behavior works for belongsTo associations only.
Just confirm about that first.

CakePHP Model with Multiple JOINS

I have a model which makes use of a table however does not really represent the table. This model shall use this table and perform multiple joins with different models, say 5 other models. Which is the best way to do this? Would you define joins separately and then merge them into one join array as seen below? Is this the best approach ?
$PlansJoin = array(
"table" => "plans_master",
"alias" => "Plan",
"type" => "INNER",
"conditions" => array(
"Plan.plan_id = KpiReporter.plan_id"
)
);
$BrandJoin = array(
"table" => "brands",
"alias" => "Brand",
"type" => "INNER",
"conditions" => array(
"Brand.brand_id = Plan.brand_id",
"OR" => array(
"Brand.brand_id" => $options["brand"],
"'all'" => $options["brand"]
)
)
);
$UserJoin = array(
"table" => "users",
"alias" => "User",
"type" => "INNER",
"conditions" => array(
"User.user_id = KpiReporter.user_id"
)
);
return $this->find("all", array(
"fields" => array_keys($this->virtualFields),
"joins" => $joins,
"group" => $group,
"conditions" => $conditions,
"order" => $order
));
Could associations be used for these complex queries ?
Why don't you use bindModel() method
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
or use containable behavior.. http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html
I've used both, and I found that containable is much more easier to implement.
it will change your life, when you are using cakephp => http://book.cakephp.org/2.0/fr/core-libraries/behaviors/containable.html
When you active this "behaviors" , in your query, juste chose your join with an array "contain"
like this :
return $this->find("all", array(
"fields" => array_keys($this->virtualFields),
"joins" => $joins,
"group" => $group,
"conditions" => $conditions,
"order" => $order,
"contain"=> array('NameOfLinkedModel')
));