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.
Related
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.
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.
I have a simple program that manages documents' data. A document has a branch_id & subject_id.
Some documents have:
a) Only the branch_id & subject_id is null.
b) Only the subject_id & branch_id is null.
c) Both the branch_id & subject_id.
I need to separate all the files by the above criteria. In my project, I used the following code to do this
if ($this->session->userdata('branch_id'))
$this->db->where('tbl_documents.branch_id', $this->session->userdata('branch_id'));
if ($this->session->userdata('subject_id'))
$this->db->where('tbl_documents.subject_id', $this->session->userdata('subject_id'));
How can I modify above code to fulfill criteria c) mentioned above. Can anyone help me?
Try the Associative array method
if (($this->session->userdata('branch_id')) && ($this->session->userdata('subject_id')))
{
$where = array(
'branch_id' => $this->session->userdata('branch_id'),
'subject_id' => $this->session->userdata('subject_id')
);
}
else if($this->session->userdata('branch_id'))
{
$where = array('branch_id' => $this->session->userdata('branch_id'));
}
else if($this->session->userdata('subject_id'))
{
$where = array('subject_id' => $this->session->userdata('subject_id'));
}
else
{
$where = array('1' => '1'); //You probably don't need this case.
}
$this->db->where($where);
$this->db->get('tbl_documents');
I don't believe you need to do anything.
Let's assume you're asking for all fields from tbl_documents so the "base-line" query statement is
SELECT * FROM tbl_documents
That will not change unless one or both of the if statements are true.
If the first is true, then the query statement becomes
SELECT * FROM tbl_documents WHERE tbl_documents.branch_id = some_branch_id;
However, if the first were false and the second true then the statement would be
SELECT * FROM tbl_documents WHERE tbl_documents.subject_id = some_subject_id;
Should both if conditions be true the query statement would be
SELECT * FROM tbl_documents WHERE tbl_documents.branch_id = some_branch_id
AND tbl_documents.subject_id = some_subject_id;
Doesn't that satisfy the criteria "c"?
The question I have is, what if both conditions are false? Is SELECT * FROM tbl_documents (no WHERE conditions) a query you actually want to run?
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
I have a page for browsing db records. The viewer can filter records by category, author, and tags. I'm using a form instead of url segments for filtering records (it feels more secure because I can validate inputs.)
For instance, when all form inputs are populated the query looks like this:
SELECT * FROM (`posts`) WHERE `category` = 'technolgy' AND `author` = 'lila' AND `tags` = 'ebook'
However if one input or more is empty, I get no results. For example:
SELECT * FROM (`posts`) WHERE `category` = '' AND `author` = 'lila' AND `tags` = ''
I want the inputs to be optional so for example if just author name is entered, I can return records made by that author regardless of category and tags. How can I omit the and where clause if empty?
Note: or_where clause is not the solution because it doesn't return a precise query if all filter inputs all filled.
My Model
function filter($form_values)
{
$query = $this->db->get('posts');
$this->db->where($form_values); //adds clause to all array items
return $query->result();
}
The function parameter is an array with input values from my view. Example,
$form_values = array('category' => $category, 'author' => $author, 'tags' => $tags);
and my View
$form_values = array (
'category' => $this->input->post('category'),
'author' => $this->input->post('author'),
'tags' => $this->input->post('tags')
);
$this->Records_model->filter($form_values);
I know that in Codeigniter if $_POST' are empty they are set to FALSE. Can that be used to achieve what I'm trying? I'm not sure if I'm on the right track
You are correct that $this->input->post() will return FALSE if the $_POST value is not set. Unless you specifically want IS NULL to be part of the query (which I believe will happen by passing FALSE to param 2 of where(), not 100% sure), just filter out the empty values:
function filter($form_values)
{
$form_values = array_filter($form_values);
// NOTE:
// where() needs to be called first, or your query won't use the WHERE clause
// You may need to make sure there is at least one value in $form_values
if ( ! empty($form_values)) // however you wish to check for a value
{
$this->db->where($form_values); //adds clause to all array items
}
$query = $this->db->get('posts');
return $query->result();
}
http://php.net/manual/en/function.array-filter.php
The important part to note on array_filter():
If no callback is supplied, all entries of input equal to FALSE (see converting to boolean) will be removed.