Laravel Eloquent with `has` and `where` on dates - sql

I try to get records on relation when there is only one record in the one to many relation and only the records where the start_date is bigger than now() and here is what I'm trying:
$newStarters = User::has('periods', 1)->with(['periods' => function($q) {
$q->where('start_date', '>', Carbon::now()->subWeek(2)->format('Y-m-d') );
}])->get();
in this case the date filter does not applies.
What is the propper way to do this?

Probably you are looking this:
$newStarters = User::whereHas('periods', function($q) {
$q->where('start_date', '>', Carbon::now()->subWeek(2)->format('Y-m-d') );
}, '=', 1)->get();
See Query relationship existence section for more details.

Related

Add where clause to calculated field in cakephp 3 query

I have a query in which I want the name of a company and its employee quantity. The thing is I want to filter this result by some conditions (like employee_number > 50 etc.). My problem is that, when building the query, I don't know how to filter this result, as the condition is set over a calculated field, so when applying the condition it gives me the below
Error: `SQLSTATE[42S22]: Column not found: 1054 Unknown column 'employee_number' in 'where clause'`.
I have been trying different things, but this is what I currently have:
$query = $this->Companies->find('all')->where($conditions)->contain(['Users']);
$query
->select(['Users.name',
'Company.modified',
'employee_number' => $query->func()->count('DISTINCT(Employees.id)')])
->where('employee_number >' => 50 )
->leftJoinWith('Employees', function (\Cake\ORM\Query $query) {
return $query->where(['deleted' => 0]);
})
->group(['Employees.company_id', 'Company.id']);
First things first, you cannot refer to an aggregate in the WHERE clause, as grouping happens afterwards, hence the error, the field employee_number doesn't exist when the WHERE conditions are being applied, you have to leverage the HAVING clause instead.
Depending on the DBMS that you are using you can reference the column from the select list, MySQL for example allows that:
$query
->select([
'Users.name',
'Company.modified',
'employee_number' => $query->func()->count('DISTINCT Employees.id')
])
->leftJoinWith('Employees', function (\Cake\ORM\Query $query) {
return $query->where(['deleted' => 0]);
})
->group(['Employees.company_id', 'Company.id'])
->having(['employee_number >' => 50]);
while Postgres for example doesn't, and requires you to repeat the aggregation inside of the HAVING clause:
->having(function (
\Cake\Database\Expression\QueryExpression $exp,
\Cake\ORM\Query $query
) {
return $exp->gt($query->func()->count('DISTINCT Employees.id'), 50);
});
ps. using DISTINCT should only be necessary when you have for example multiple joins that would result in duplicate joined rows.
See also
Cookbook > Database Access & ORM > Query Builder > Aggregates - Group and Having

"andFilterWhere" work proper with "joinWith()" but not with "with()" in yii2

I am working in yii2.
There are employee and company table employee contains company_id.
I have a filter search running properly If I use joinWith()
$query = Employee::find();
$query->joinWith(['company']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => false,
'sort' => false,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
//and below is the filterwhere
$query->andFilterWhere(['like', 'company.name', $this->company_id]);
But issue came when I make a query using with()
$query = Employee::find()->with(['company']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => false,
'sort' => false,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
//when query contain with() then this filter is not working.
$query->andFilterWhere(['like', 'company.name', $this->company_id]);
This gives error when I use with()
Database Exception – yii\db\Exception
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'company.name' in 'where clause'
The SQL being executed was: SELECT COUNT(*) FROM `employee` WHERE `company`.`name` LIKE '%1%'
Here is the relation in employee with company:
public function getCompany(){
return $this->hasOne(Company::className(), ['id'=> 'company_id']);
}
Can anyone help me or guide me how could I filter data properly using with() in a query?
Thanks.
You can't swap joinWith() and with() methods when you need to filter by the column from the related table. That's because these methods does completely different things.
Methods like joinWith() and join() actually modifies the query to add the "JOIN" part to the SQL query. The with in joinWith allows you to specify the joined table by the relation definition in the model. The eager loading in joinWith is only side effect and you can even turn that off by passing false as second parameter.
When you do:
Employee::find()->joinWith(['company'])->all();
The query that is run looks like:
SELECT * FROM employee LEFT JOIN company ON (...)
On the other side the method with() doesn't modify the query itself. It only forces the eager loading of related models. In reality the second query is used for preloading the related records.
When you do:
Employee::find()->with(['company'])->all();
It actually runs queries like these:
SELECT * FROM employee;
SELECT * FROM company WHERE id IN (...company ids selected in first query...);
So when you try to do:
$query = Employee::find()
->with(['company'])
->andFilterWhere(['like', 'company.name', $this->company_id])
->all();
The generated query is
SELECT * FROM employee WHERE company.name LIKE ...

Laravel Elequent Count from Multiple Columns

I'm trying to get the count of 2 columns('published', 'expires') in Laravel 5.6.
I want my results count to only show if the item is published, not expired or there is no expiration date.
my code:
$today = date('Y-m-d');
$numrecords = deals::where('published',1)
->orwhereDate('expires', '=', '')
->orwhereDate('expires', '>=', $today)
->count();
thanks
Nabi
$numrecords = deals::where('published', 1)
->where(function($q){
return $q->whereNull('expires')
->orwhereDate('expires', '>=', Carbon::today());
})
->count();
Above should give you :
SELECT * FROM deals
WHERE
published = 1 AND
( expires IS NULL OR DATE(expires) >= today_date)
Here are the queries you are supposed to write: (today is a Laravel function)
// 1. if the item is published
$item->where('published', true);
// 2. expire date is after today
$item->where('expiry_date', '>', today());
// 3. expire date is null
$item->whereNull('expiry_date');
//4. emit expired items
$item->where('expiry_date', '>', today());
I think some of your check conditions are wrong.
Also, your logic is very messy as well. I am not sure what condition you are trying to write, but do write it down, under what condition, is an item considered into the count, then you decide to use where or orWhere.

Multiple joins using active record with YII framework

im getting stuck with active record for yii.
im using models for each table in my db.
the sql i try to get is querying and joining from 3 tables.
what i want to accomplish is the equivalent of the sql command :
SELECT location_code as stopkey, bay_no bay_no, description stop_name, route_area_code route_area_code, latitude latitude, longitude, build_code build_code, message_time message_time, ip_address ip_address, route.route_code route, make make, last_impact last_impact, impact_count impact_count, last_bootup last_bootup, bootup_count bootup_count, last_active_hour last_active_hour, last_active_day last_active_day, operator.operator_code operator_code, routes routes, bearing
FROM snapshot_stop_status route
JOIN route_visibility ON route.route_id = route_visibility.route_id
JOIN operator ON operator.operator_id = route_visibility.operator_id
WHERE usernm = 'me'
ORDER BY location_code
here is what i tried so far :
public function relations() {
return array(
'RoutesVisibility' =>array(self::MANY_MANY,'route_visibility','route_id'),
);
}
How can i accomplish this using relations function in the models ?
any kind of help would be appreciated
route_visibility is the joining table that tie operator to snapshot_stop_status. So in yii you can specify the table doing the relations:
'operators' =>array(self::MANY_MANY,'Operator','route_visibility(route_id,operator_id )'),
And in Operator:
'routes' =>array(self::MANY_MANY,'Route','route_visibility(operator_id, route_id)'),
Then you can request with something like:
$criteria = new CDbCriteria;
$criteria->with = array('operators' => array('condition' => 'usernm = "me"'));
$models => Route:model()->findAll($criteria);

'OR' in NHibernate Lambda Extensions

How can I union two criteria with an OR statement?
For example I want to get Employee which has null in Birthday field OR value of this field is less than someDate. How should I rewrite this code:
var query = DetachedCriteria.For<Employee>()
.Add(SqlExpression.IsNull<Employee>(p => p.Birthday))
.Add<Employee>(emp => emp.Birthday.Value < someDate);
You need to use Disjunction()