Symfony doctrine group by max date timestamp - php

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();

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

How to bind datetime field between two string value

I have method like this :
public function getCustomDateOrders(string $startDay,string $endDay,string $food) :array
{
$result = $this->_em->createQueryBuilder()
->select
(
'OrderEntity.name'
'OrderEntity.created'
)
->from($this->entityClass , 'OrderEntity')
->leftJoin(
'Directory\Food',
'Food',
'with',
'Food.id = OrderEntity.FoodId '
)
->where("Food.id =:food")
->andWhere("OrderEntity.status =:active")
->andWhere("startDate<:OrderEntity.orderCreated >:endDay")
->getQuery()
->setParameters([
"food" => $food,
"active" => 1,
"startDate" => $startDay,
"endDay" => $endDay
])
->getScalerResult();
->getScalarResult();
}
I have couple of values :
$startDay is equal to "2016-010-17 00:00:00" (string)
$endDay is equal to "2016-10-03 00:00:00" (string)
And also order.created (one of order's fields) is datetime.
I want to fetch order from order entity which has created field is between $startDay and $endDay. How to solve it?
Use between:
public function getCustomDateOrders(string $startDay,string $endDay,string $food) :array
{
$result = $this->_em->createQueryBuilder()
->select
(
'OrderEntity.name'
'OrderEntity.created'
)
->from($this->entityClass , 'OrderEntity')
->leftJoin(
'Directory\Food',
'Food',
'with',
'Food.id = OrderEntity.FoodId '
)
->where("Food.id =:food")
->andWhere("OrderEntity.status =:active")
->andWhere("OrderEntity.orderCreated between :startDay and :endDay")
->setParameters([
"food" => $food,
"active" => 1,
"startDay" => $startDay,
"endDay" => $endDay
])
->getQuery()
->getScalerResult();
}
And that is why we don't store dates as strings. You can still convert the string inside the query, so don't just turn off the computer yet.
Use the str_to_date() function:
Lets translate it into SQL:
select * from yourtable
where created > str_to_date(start_day, '%Y-%m-%d %H:%i:%s')
and created < str_to_date(end_day, '%Y-%m-%d %H:%i:%s')
There we go. Give me all the rows which where created after the start_date and before the end date.
The better way would probabbly be converting your strings to dates and the use between like sugested.

how to make the model->search function in yii2 not return rows with null values

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]]);

how to use not null condition in YII2

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']);

Categories