I have this query which is working fine
$order_items= OrderItem::find()
->where(['location_id'=>$model->location_name,'instructor_id'=>$model->instructor_name])
->andwhere(['between', 'date', $model->from_date, $model->to_date ])->all();
But when $model->instructor_name is empty or null, I am getting Null result.
So I want to ignore when instructor_id is Null
when
'instructor_id'=>$model->instructor_name or instructor_id'=> Null
how I can do that?
You should use andFilterWhere()
$order_items = OrderItem::find()
->where(['location_id' => $model->location_name])
->andFilterWhere(['instructor_id' => $model->instructor_name])
->andwhere(['between', 'date', $model->from_date, $model->to_date ])
->all();
$order_items= OrderItem::find()
->where(['location_id'=>$model->location_name,'instructor_id'=>$model->instructor_name])
->andWhere(['not', ['instructor_id' => null]])
->andwhere(['between', 'date', $model->from_date, $model->to_date ])->all();
Or add the following
->andWhere(['<>', 'instructor_id', null])
Or
->andWhere('instructor_id IS NOT NULL')
Related
I would like to select values from table o by some conditions and grouped by groupKey. This query is working fine, but now query return first grouped value for my. I need to retrieve grouped values with MAX timestamp.
An example if there are two or more values with groupKey I need that one where o.createdAt value is newer.
$qb = $this->createQueryBuilder('order');
$expr = $qb->expr();
return $qb
->select('order, (CASE WHEN order.tsmOrderNumber IS NOT NULL THEN order.tsmOrderNumber ELSE order.id END) as groupKey')
->where('order.user =:user')
->andWhere('order.status =:status')
->andWhere(
$expr->orX(
$expr->andX(
$expr->isNotNull('order.wayBillNumber'),
$expr->neq('order.wayBillNumber', "''"),
$expr->between('order.createdAt', ':dateFrom', ':dateTo')
),
$expr->andX(
$expr->orX(
$expr->isNull('o.tsmNumber'),
$expr->eq('o.tsmNumber', '\'\'')
),
$expr->between('order.createdAt', ':dateFrom2', ':dateTo')
)
)
)
->setParameters(
[
'status' => Order::STATUS_COMPLETED,
'user' => $user,
'dateFrom' => (new \DateTime())->modify('-2 month'),
'dateFrom2' => (new \DateTime())->modify('-6 month'),
'dateTo' => new \DateTime()
]
)
->groupBy('groupKey')
->orderBy('order.createdAt', 'DESC')
->getQuery()
->getResult();
How do I write this kind of COALESCE() statement in the query builder?
SQL
SELECT COALESCE(n.value, p.value) AS value
FROM nodes n
LEFT JOIN parents p ON p.id = n.parent_id
PHP
I can retrieve both the child and parent values and then go through the result set and just use the parent one if the child one is empty, but if there is a more elegant way to build it into the query itself, I would prefer that.
$child = $this->Nodes->find()
->select(['id', 'value'])
->where(['Nodes.id' => $id])
->contain([
'Parents' => function ($q) {
return $q->select('value');
}
])
->first();
if (empty($child->value)) {
$child->value = $child->parent->value;
}
Update 1
So this is what I have at the moment, but it doesn't work.
$child = $this->Nodes->find()
->select(['id', 'value'])
->where(['Nodes.id' => $id])
->contain([
'Parents' => function ($q) {
return $q->select([
'value' => $q->func()->coalesce([
'Nodes.value',
'Parents.value'
])
]);
}
])
->first();
Returns:
object(Cake\ORM\Entity) {
'id' => (int) 234,
'value' => (float) 0,
'[new]' => false,
'[accessible]' => [
'*' => true
],
'[dirty]' => [],
'[original]' => [],
'[virtual]' => [],
'[errors]' => [],
'[invalid]' => [],
'[repository]' => 'Nodes'
}
The child value is NULL and the parent value is 1.00 so I would expect the entity value to be 'value' => (float) 1.00 but I assume it's coming out of the query as FALSE converted to (float) 0.
Update 2
It seems aliasing the coalesce to a name which already exists as a normal field does not work. It requires a unique field name for the coalesce result.
Update 3
I did another test and selected the name field from the two tables instead, and it just returns the actual strings I entered into the function (they do not get evaluated as column names):
return $q->select([
'value' => $q->func()->coalesce([
'Nodes.name',
'Parents.name'
])
]);
The returned entity has:
'value' => 'Nodes.name'
So my new question would be how to get the query builder to evaluate the strings as table/field names?
I could not get Cake's coalesce() function to evaluate the parameters as fields, it was just returning the actual strings of the field names.
I got it working by manually creating the COALESCE statement instead.
// Create the query object first, so it can be used to create a SQL expression
$query = $this->Nodes->find();
// Modify the query
$query
->select([
'id',
'value' => $query->newExpr('COALESCE(Nodes.value, Parents.value)')
])
->where(['Nodes.id' => $id])
->contain('Parents')
->first();
CakePHP's coalesce() uses the following format to differentiate field names from literal values:
'value' => $q->func()->coalesce([
'User.last_name' => 'identifier',
', ',
'User.first_name' => 'identifier'
])
The code above should yield results like Smith, John.
The default behavior is to treat the element as a literal.
See https://api.cakephp.org/3.3/class-Cake.Database.FunctionsBuilder.html#_coalesce
The docs don't explain this well at all. H/T to https://www.dereuromark.de/2020/02/06/virtual-query-fields-in-cakephp/ for a clear example.
See http://book.cakephp.org/3.0/en/orm/query-builder.html#using-sql-functions
Haven't tried it but I guess it's:
$child = $this->Nodes->find()
->select(['id', 'value'])
->where(['Nodes.id' => $id])
->contain([
'Parents' => function ($q) {
return $q->select(['value' => $query->func()->coalesce([
/* Fields go here... I think. :) */
])]);
}
])
->first();
If this isn't working check the unit tests of the core how to call this function.
so i have a model that has relations and i've modified the search function to permit querying the relational data but i don't want it to return the entries which have null values inside them. here's my search function:
public function search($params)
{
$query = Services::find();
$query->joinWith(['location', 'client', 'operator']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort'=> ['defaultOrder' => ['date'=>SORT_ASC]]
]);
...
$query->andFilterWhere([
'id' => $this->id,
'tip' => $this->tip,
'status' => $this->status,
]);
if ( ! is_null($this->date) && strpos($this->date, ' - ') !== false ) {
$datelist = explode(' - ', $this->date);
// var_dump($datelist);
// die($datelist);
$start_date = \DateTime::createFromFormat('m-d-Y H:i:s', $datelist[0].' 00:00:00');
$end_date = \DateTime::createFromFormat('m-d-Y H:i:s', $datelist[1].' 23:59:59');
$query->andFilterWhere(['between', 'date', $start_date->format('Y-m-d H:i:s'),$end_date->format('Y-m-d H:i:s')]);
}
$query->andFilterWhere(['like', 'location.address', $this->location]);
$query->andFilterWhere(['like', 'client.name', $this->client]);
$query->andFilterWhere(['like', 'personal.nume', $this->operator_id]);
$query->andFilterWhere(['NOT', [$this->client=>null]]);
$query->andFilterWhere(['NOT', [$this->location=>null]]);
$query->andFilterWhere(['NOT', ['location_id' => null]]);
$query->andFilterWhere(['NOT', ['client_id' => null]]);
return $dataProvider;
}
Notice the last 4 query rows. I think that should omit the rows that have null values in those specific attributes
This is the query generated, it does not include any NOT conditions and i don't get why.
SELECT `services`.* FROM `services` LEFT JOIN `location` ON `services`.`location_id` = `location`.`id` LEFT JOIN `client` ON `services`.`client_id` = `client`.`id` LEFT JOIN `personal` ON `services`.`operator_id` = `personal`.`id` WHERE `date` BETWEEN '2015-01-01 00:00:00' AND '2015-01-22 23:59:59' ORDER BY `client`.`name` DESC LIMIT 20
If someone manages to do this before, please show how :D
Thank you in advance
Instead of using andFilterWhere use andWhere. andFilterWhere ignores the empty operands and thus your null values will not be added to the query.
Replace
$query->andFilterWhere(['NOT', [$this->client=>null]]);
$query->andFilterWhere(['NOT', [$this->location=>null]]);
$query->andFilterWhere(['NOT', ['location_id' => null]]);
$query->andFilterWhere(['NOT', ['client_id' => null]]);
With
$query->andWhere(['NOT',['location_id' => null]])
$query->andWhere(['NOT', ['client_id' => null]]);
Hi i want to use not null condition in my yii2 query how should i use that.
i don't want city and state null.
My query is
$query = new Query;
$query->select('ID, City,State,StudentName')
->from('student')
->where(['IsActive' => 1])
->orderBy(['rand()' => SORT_DESC])
->limit(10);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => false,
]);
You can use the not operator combined with the fields that should not be null to generate a IS NOT NULL SQL statement. Like this:
$query = new Query;
$query->select('ID, City,State,StudentName')
->from('student')
->where(['IsActive' => 1])
->andWhere(['not', ['City' => null]])
->andWhere(['not', ['State' => null]])
->orderBy(['rand()' => SORT_DESC])
->limit(10);
Also check the examples in the documentation.
->where(['IS NOT', 'column', null]);
get
WHERE column IS NOT NULL
You can also use, it is faster to type
->where('column IS NOT NULL')
In complex query
->where(['AND',
'column1 IS NOT NULL', // works
['IS NOT', 'column2', null], // works
['column3' => $value],
)
One of the options will be:
$query = new Query;
$query->select('ID, City,State,StudentName')
->from('student')
->where(['IsActive' => 1])
->andWhere(['<>', 'City', null])
->andWhere(['<>', 'State', null])
->orderBy(['rand()' => SORT_DESC])
->limit(10);
Check official docs for where.
$items = BadOffer::find()->where(['OR',
['IS', 'moderator_id', (new Expression('Null'))],
['moderator_id' => $user->id],
]);
In Yii2, we can use any of the queries below to verify the null condition,
->andWhere(['NOT', ['city' => null]]);
or
->andWhere(['<>', ['city' => null]]);
or
->andWhere('city IS NOT NULL');
use ->andWhere(['not', ['State' => null]]) or ->andWhere(['is not', 'State', null]);
Do no use :
andFilterWhere, as the null will make this filter be ignored
->andWhere(['<>', 'State', null]) as it form query AND State <> null
How to select non-empty columns in MySQL?
use LENGTH :
SELECT col1
FROM table
WHERE LENGTH(col1) > 0
Yii2 :
->andWhere(['>', 'LENGTH(col1)', 0])
This work for me, but only when pass null as string
->andFilterWhere(['<>', '`city`', 'null']);
I'm using propel master-dev with symfony 2.1.
Is possible to write something like that ? Else how can I add an alias to the select statement.
$products = ProdottinewQuery::create()
->leftJoinWith('Prodotticolori')
->leftJoinWith('Alberocategorie')
->leftJoinWith('Brand')
->leftJoinWith('Prodottimateriali')
->leftJoinWith('Prodottigroffatura')
->select(array('id',
'codice',
'nomeEng',
'Alberocategorie.nomeeng' => 'category',
'Prodotticolori.coloreeng' => 'color',
'Brand.brand' => 'brand',
'Prodottimateriali.materialeeng' => 'material',
'Prodottigroffatura.groffaturaeng' => 'groffage'))
->orderById()
->limit($howmany)
->find();
Resolved:
$products = ProdottinewQuery::create()
->leftJoinWith('Prodotticolori')
->leftJoinWith('Alberocategorie')
->leftJoinWith('Brand')
->leftJoinWith('Prodottimateriali')
->leftJoinWith('Prodottigroffatura')
->select(array('id',
'codice',
'nomeEng'))
->withColumn('Alberocategorie.nomeeng', 'category')
->withColumn('Prodotticolori.coloreeng', 'color')
->withColumn('Brand.brand', 'brand')
->withColumn('Prodottimateriali.materialeeng', 'material')
->withColumn('Prodottigroffatura.groffaturaeng', 'groffage')
->orderById()
->limit($howmany)
->find();