How to ignore where clause if condition is empty in Yii2 - php

I know this same question is already asked before. But I have tried the solution but it's not working for me.
$comp_ids = AllowArea::find()
->select(['comp_code'])
->where(['user_id' => Yii::$app->user->id])
->column();
$ref = (new \yii\db\Query())
->select([
'ProductCode',
'ProductNameFull',
'ProductSpec',
'ProductGroup',
'CompanyCode',
'CompanyName'
,'Price',
'PurchasePrice'
])->from('Product')
->andFilterWhere(['CompanyCode' => $comp_ids])
->all(Yii::$app->sds);
It's giving me empty data.
Flow
The users are assigned areas and some users are assigned areas with a company. So I want the above query to return me the result whether the condition fails or not.
Update 1
The SQL which I am getting is
SELECT `ProductCode`, `ProductNameFull`, `ProductSpec`, `ProductGroup`,
`CompanyCode`, `CompanyName`,
`Price`, `PurchasePrice` FROM `Product` WHERE `CompanyCode` IS NULL
Any help would be highly appreciated.

If nothing works, from what you were told, then you can try:
$ref = (new \yii\db\Query())
->select([
'ProductCode',
'ProductNameFull',
'ProductSpec',
'ProductGroup',
'CompanyCode',
'CompanyName'
,'Price',
'PurchasePrice'
])->from('Product');
if (!empty($comp_ids)) {
$ref->andFilterWhere(['CompanyCode' => $comp_ids]);
}
$ref = $ref->all(Yii::$app->sds);

Try user orFilterWhere() this Adds an additional WHERE condition to the existing one but ignores empty operands.
The new condition and the existing one will be joined using the 'OR' operator.
This method is similar to orWhere(). The main difference is that this method will remove empty query operands. As a result, this method is best suited for building query conditions based on filter values entered by users.

Related

CakePHP 3 putting un-necessary parentheses in SQL causing error

CakePHP 3.7. Trying to use the ORM to write a query which contains a MySQL COALESCE condition.
Followed advice on CakePHP 3 - How to write COALESCE(...) in query builder? and ended up having to write it manually using newExpr() as this was the given solution.
The code I have is as follows:
$TblRegulatoryAlerts = TableRegistry::getTableLocator()->get('TblRegulatoryAlerts');
$subscribed_to = $TblRegulatoryAlerts->getUserRegulations($u_id, $o_id, false);
$query = $this->find()
->contain('Filters.Groups.Regulations')
->select(['id', 'date', 'comment', 'Filters.label', 'Filters.anchor', 'Groups.label']);
$query->select($query->newExpr('COALESCE((SELECT COUNT(*)
FROM revision_filters_substances
WHERE revision_filter_id = RevisionFilters.id), 0) AS count_substances'));
$query->where(['date >=' => $date_start, 'date <=' => $date_end, 'Regulations.id' => $regulation_id, 'Filters.id IN' => $subscribed_to]);
$query->enableHydration(false)->orderDesc('date');
This produces the following SQL (output of debug($query->sql()):
SELECT RevisionFilters.id AS `RevisionFilters__id`, RevisionFilters.date AS `RevisionFilters__date`, RevisionFilters.comment AS `RevisionFilters__comment`, Filters.label AS `Filters__label`, Filters.anchor AS `Filters__anchor`, Groups.label AS `Groups__label`, (COALESCE((SELECT COUNT(*) FROM revision_filters_substances WHERE revision_filter_id = RevisionFilters.id), 0) AS count_substances) FROM revision_filters RevisionFilters INNER JOIN dev_hub_subdb.filters Filters ON Filters.id = (RevisionFilters.filter_id) INNER JOIN dev_hub_subdb.groups Groups ON Groups.id = (Filters.group_id) INNER JOIN dev_hub_subdb.regulations Regulations ON Regulations.id = (Groups.regulation_id) WHERE ...
Unfortunately this doesn't execute because Cake is putting in un-necessary parentheses surrounding the COALESCE statement, which changes the SQL.
In the above code it generates:
(COALESCE((SELECT COUNT(*) FROM revision_filters_substances WHERE revision_filter_id = RevisionFilters.id), 0) AS count_substances)
Whereas it needs to omit the parentheses surrounding COALESCE so it's just:
COALESCE((SELECT COUNT(*) FROM revision_filters_substances WHERE revision_filter_id = RevisionFilters.id), 0) AS count_substances
Is this possible?
Don't specify the alias in the expression, instead specify it using the key => value syntax of the Query::select() method, like this:
$query->select([
'count_substances' => $query->newExpr('...')
]);
It would still wrap the expression in parentheses, but that would then be valid as it doesn't include the alias.
That being said, using the function builders coalesque() method should work fine, the problem described in the linked question can be fixed by using the key => value syntax too, where the value can specify the kind of the argument, like ['Nodes.value' => 'identifier'], without that it would bind the value as a string.
However there shouldn't be any such problem with your example, using the function builders coalesce() method should work fine.
$query->select([
'count_substances' => $query->func()->coalesce($countSubquery, 1, ['integer'])
]);
The type argument is kinda optional, it would work with most DBMS without it, but for maximum compatibility it should be specified so that the integer value is being bound properly, also it will automatically set the return type of the function (the casting type) to integer too.

Yii2 - Ignore where clause if variable is empty

I have yii2 query with conditional where clause. this is my query :
$query = new Query();
$query->select
(['pengeluaran.id'])
->from('surat_jalan, pengeluaran')
->where('surat_jalan.no_bus=:no_bus',['no_bus'=>$no_bus])
//this is my conditional query
->andWhere(['between', 'pengeluaran.tgl_pengeluaran', $awal, $akhir])
->andWhere('pengeluaran.nama_toko=:nama_toko',['nama_toko'=>$nama_toko])
->andWhere('pengeluaran.metode_pembayaran=:metode_pembayaran',['metode_pembayaran'=>$metode_pembayaran])
->andWhere('pengeluaran.waktu_pembayaran=:waktu_pembayaran',['waktu_pembayaran'=>$waktu_pembayaran])
//this is my conditional query
->andWhere('surat_jalan.id_surat_jalan=pengeluaran.id_surat_jalan');
$command = $query->createCommand();
$data_id_pengeluaran = $command->queryAll();
I read some question from others and what I found is for mysql table field :
->andWhere(['not', ['activated_at' => null]]);
what I want is if the variable is empty, the conditional where() clause is ignore. Is it possible in yii2??
The filterWhere is the perfect tool to achieve your goals.
For example,
// This will not appear in the finally statement if $val is empty.
$query->andFilterWhere(['activated_at' => $val])
Note: A value is considered empty if it is null, an empty array, an empty string or a string consisting of whitespaces only.

How to compare against fields that are `null` (empty)?

I have a table in a CakePHP 3 application called downloads which has a column called master. The field type is set to TINYINT(1)
I can find any records where downloads.master == 1 like this:
$query = $this->Downloads->find()->where(['master' => true]);
But Cake won't let me query for ones where downloads.master !== 1. None of these work, and all return an empty array/object when the query is executed:
$query = $this->Downloads->find()->where(['master' => false]);
$query = $this->Downloads->find()->where(['master' => 0]);
$query = $this->Downloads->find()->where(['master' => null]);
$query = $this->Downloads->find()->where(['master' => '']);
What do you use as the condition to make this possible? My thinking was that it should be false since that's the opposite to true, but as with most things in CakePHP 3 they like to make it more complicated than necessary...
I've examined the records in my table using phpMyAdmin and there are indeed both records where master == 1 and master == null so it's not a case of there's zero results to return.
A column being NULL is not the same as being 0 (ie false-ish from the point of view of the ORM in case of a boolean-ish column type). If you want to compare against NULL, then you must issue a query with IS NULL, which is a SQL/DBMS requirement, not a CakePHP requirement.
CakePHP however requires you to be specific about what you want to do, as passing null does not neccesarily have to mean that you want to compare against SQL NULL, depending on the context.
Long story short, use the IS operator:
where(['master IS' => null])
Similarly use IS NOT for a negated condition. You can also pass user input as the value, the ORM will test the value and convert the IS and IS NOT operators into = and != respectively in case a non-null value is being passed.
See also
Cookbook > Database Access & ORM > Query Builder > Automatic IS NULL Creation

InnerJoin in CakePHP 3 returns no rows

I am trying to learn CakePHP 3, but I have run into a problem:
I have two tables languages and rich_text_elements, and want to join them in the following manner:
$all = $this->find()->
select(['i18n','Language.long_name'])->
innerJoin(['Language' => 'languages'], ['Language.i18n' => 'RichTextElements.i18n'])->
group('RichTextElements.i18n')->
order(['RichTextElements.i18n'])->all();
The following query is produced:
SELECT RichTextElements.i18n AS `RichTextElements__i18n`,
Language.long_name AS `Language__long_name`
FROM rich_text_elements RichTextElements
INNER JOIN languages Language ON Language.i18n = :c0
GROUP BY RichTextElements.i18n ORDER BY RichTextElements.i18n;
If I replace ":c0" with "RichTextElements.i18n", this query runs fine alone (in HeidiSql) and returns five rows of data, exactly as I expect it to.
But CakePHP returns an empty set!
The problem seem related to the innerJoin() because if I modify the query to select only from the RichTextElements table, it will return five rows as expected, in CakePHP:
Runs fine:
$all = $this->find()->
select(['i18n'])->
group('RichTextElements.i18n')->
order(['RichTextElements.i18n'])->all();
Anyone see what I don't see?
As stated in the API:
Conditions can be expressed [...] using a string for comparing columns, or string with already quoted literal values. Additionally it is possible to use conditions expressed in arrays or expression objects.
Taken from Query::join() | Using conditions and types.
Try the following:
$all = $this->find()
->select(['i18n','Language.long_name'])
->innerJoin(
['Language' => 'languages'],
['Language.i18n' => new \Cake\Database\Expression\IdentifierExpression('RichTextElements.i18n')])
->group('RichTextElements.i18n')
->order(['RichTextElements.i18n'])->all();
This should also work:
$all = $this->find()
->select(['i18n','Language.long_name'])
->innerJoin(
['Language' => 'languages'],
['Language.i18n = RichTextElements.i18n'])
->group('RichTextElements.i18n')
->order(['RichTextElements.i18n'])->all();

Cakephp SQL Error 1054 Unknown Column In The Field List

I am trying to update multiple records in one field in my database. For some reason I keep getting SQL Error: 1054: Unknown column '520947b9' in 'field list'. 502947B9 is apart of my ID. Im not understanding why that value is being seen as a field list. Here is my code. That said, Im not sure Im updating these records correctly. If Im not please point it out to me. Thanks!!
public function findPolicyIds($coverageId = null) {
$policyid = $this->Policy->find('all', array(
'recursive' => -1,
'conditions' => array('Policy.coverage_id' => $coverageId),
'fields' => array('Policy.id')));
foreach($policyid as $id) {
$all[] = $id['Policy']['id'];
foreach ($all as $key) {
$this->Policy->Declination->updateAll(
array('Declination.policy_id' => $key),
array('Declination.coverage_id <=' => $coverageId)
);
}
}
}
Here are my errors
Query: UPDATE declinations AS Declination LEFT JOIN policies AS Policy ON (Declination.policy_id = Policy.id) SET Declination.policy_id = 520947b9-0210-4067-94ea-70f8ae78509d WHERE Declination.coverage_id <= '520947b9-1fa0-45db-992e-70f8ae78509d'
Query: UPDATE declinations AS Declination LEFT JOIN policies AS Policy ON (Declination.policy_id = Policy.id) SET Declination.policy_id = 520947b9-0694-4724-b353-70f8ae78509d WHERE Declination.coverage_id <= '520947b9-1fa0-45db-992e-70f8ae78509d'
By the looks of your query, updateAll is not recognizing $key as a string. Either cast it as such, or add the ' characters yourself. Example:
$this->Policy->Declination->updateAll(
array('Declination.policy_id' => "'".$key."'"),
array('Declination.coverage_id <=' => $coverageId)
);
That's the SQL error.
Now
"That said, Im not sure Im updating these records correctly."
... Well, what do you want to do? Reading your code, You are getting an array of Policy's ids and updating all Declinations with a coverage_id <= $coverageId, which doesn't make much sense, since that foreach is updating the policy_id for that same condition, so in the end you will perceive the last change: last policy_id of the foreach on every Declination with coverage_id equal or less than $coverage_id.... Doesn't make much sense to me, even not knowing what you need to do.
Based on the SQL and assuming you are using an ORM, it appears to me that policy_id is defined as an numeric field in your Declination model when it really needs to be a string. Coverage_id field is working correctly, so compare the two definitions.

Categories