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()
Related
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
For example we have model TableRow - columns (:account_number, :month, :department, :phone_number). And have a method that returns filtered rows by arrays of this params.
For required params we can use
TableRow.where('account_number IN (?)', param)
Is there best way to add in this query unrequired params (department, phone_number) that can be nill and we should return records with any params in this column?
There are a couple ways to approach this. If you want your query to be static, you can check the literal value of your param with the SQL logic itself:
TableRow.where('COALESCE(:depts) IS NULL OR department IN (:depts)', depts: param)
You can also build up your relation incrementally in Ruby:
relation = TableRow.all
relation = relation.where(department: depts) if depts.present?
Your question is hard to understand, but if what you want is to filter by phone_number while still retrieving records where phone_number is null, you just have to that:
TableRow.where('phone_number IN (?)', param << nil)
I need help to convert following ql query to Linq to Sql query.
select Name, Address
from Entity
group by Name, Address
having count(distinct LinkedTo) = 1
Idea is to find all unique Name, Address pairs who only have 1 distinct LinkedTo value. Remember that there are other columns in the table as well.
I would try something like this:
Entity.GroupBy(e => new { e.Name, e.Address})
.Where(g => g.Select(e => e.LinkedTo).Distinct().Count() == 1)
.Select(g => g.Key);
You should put a breakpoint after that line and check the SQL that is generated to find what is really going to the database.
You could use:
from ent in Entities
group ent by new { ent.Name, ent.Address } into grouped
where grouped.Select(g => g.LinkedTo).Distinct().Count() == 1
select new { grouped.Key.Name, grouped.Key.Address }
The generated SQL does not use a having clause. I'm not sure LINQ can generate that.
I have query:
var query = this.session.QueryOver<Products>()
.Where(uic => uic.PageNumber == nextPage[0])
.SingleOrDefault(uic => uic.ProductNumber)
But this query result is type Products. It is possible that result will be only integer type of column ProductNumber ?
Try something like this:
var query = this.session.QueryOver<Products>()
.Where(uic => uic.PageNumber == nextPage[0])
.Select(uic => uic.ProductNumber)
.SingleOrDefault<int>();
Since you need a single primitive type value, you can do .Select to define the result column, and then do .SingleOrDefault to get the only result. For complex types, you'd need to use transformers.
You can find more info about QueryOver in this blog post on nhibernate.info: http://nhibernate.info/blog/2009/12/17/queryover-in-nh-3-0.html
You can use Miroslav's answer for QueryOver, but this would look cleaner with LINQ:
var productNumber = session.Query<Products>()
.Where(uic => uic.PageNumber == nextPage[0])
.Select(uic => uic.ProductNumber)
.SingleOrDefault();
Notice you don't need a cast, as the Select operator changes the expression type to the return type of its parameter (which is the type of ProductNumber).
I have several complex queries (using subqueries, etc...) and want to glue them together with OR or AND statement.
For example:
where1=table.where(...)
where2=table.where(...)
I would like something like
where3=where1.or where2
Next example doesn't work for me:
users.where(users[:name].eq('bob').or(users[:age].lt(25)))
because of I have several where(..) queries and I want to concatenate them.
In other words
I have 3 methods: first return first where, second-second, third - OR concatenation.
I must have able to use all 3 methods in my application and save DRY code
are you looking for the form:
users.where(users[:name].eq('bob').or(users[:age].lt(25)))
docs: https://github.com/rails/arel
users.where(users[:name].eq('bob').or(users[:age].lt(25))) is close, but you need to get the arel_table to specify the columns, e.g.
t = User.arel_table
User.where(t[:name].eq('bob').or(t[:age].lt(25)))
I know that for AND concatenation you can do:
users = User.where(:name => 'jack')
users = users.where(:job => 'developer')
and you get a concatenation with AND in SQL (try it with #to_sql at the end)
Other than that you can do:
where1=table.where(...)
where2=table.where(...)
where1 & where2
example:
(User.where(:name => 'jack') & User.where(:job => 'dev')).to_sql
=> "SELECT `users`.* FROM `users` WHERE `users`.`name` = 'jack' AND `users`.`job` = 'dev'"