How can you do a conditional where clause using AREL
It is possible to chain where statements
residentials = Residential.where(:is_active => true)
residentials = residentials.where(:other_thing => true) if param_was_passed
This should work.
Make sure this is not the last line in a function call; repeat the residentials
variable as the last line in that case. (As per @digger69 comment)
How to add conditional where clauses in rails
You can apply multiple where
calls to a query so you can build your base query:
query = User.joins(...)
.group(...)
.select(...)
.where('users.id = :user_id', :user_id => self.id)
and then add another where
call depending on your date interval:
if(begin_date && end_date)
query = query.where(:created_at => begin_date .. end_date)
# or where('created_at between :begin_date and :end_date', :begin_date => begin_date, :end_date => end_date)
elsif(begin_date)
query = query.where('created_at >= :begin_date', :begin_date => begin_date)
elsif(end_date)
query = query.where('created_at <= :end_date', :end_date => end_date)
end
Each where
call adds another piece to your overall WHERE clause using AND so something like:
q = M.where(a).where(b).where(c)
is the same as saying WHERE a AND b AND c
.
Conditionally chaining where clauses in Rails ActiveRecord queries
Queries aren't strings; they're query objects. So you want something like
query = YourModel.scoped # Rails 3; in Rails 4, use .all
if params.has_key?('size')
query = query.where(size: params['size'])
end
etc.
Can you add clauses in a where block conditionally when using Squeel?
So, this isn't the prettiest thing ever, but it does what you're after.
def self.by_any(sin, name, dob)
where do
[
sin.presence && clients.sin == "#{sin}",
name.presence && clients.name =~ "%#{name}",
dob.presence && clients.dob == "#{dob}"
].compact.reduce(:|)
# compact to remove the nils, reduce to combine the cases with |
end
end
Basically, [a, b, c].reduce(:f)
returns (a.f(b)).f(c)
. In this case f
, the method invoked, is the pipe, so we get (a.|(b)).|(c)
which, in less confusing notation, is (a | b) | c
.
It works because, in Squeel, the predicate operators (==
, =~
, and so on) return a Predicate
node, so we can construct them independently before joining them with |
.
In the case where all three are nil
, it returns all records.
How to combine two conditions in a where clause?
solution 1: ( I prefer , more easy to understand)
Just write it like raw SQL:
Comment.where(
"(user_id > ? AND user_id < ? ) OR (created_at > ? AND created_at < ?)",
100, 200, "2022-06-01", "2022-06-05")
solution 2:
Comment.
where(:created_at => time_range).
where("user_id is not in (?)",[user_ids])
which will produce SQL like : select ... where ... AND ...
conditional active record query with rails
As commented above, you need to generate SQL with the IS
keyword to determine if a column is NULL
. Rather than wrangle this yourself, you can pass a hash to where
and let ActiveRecord handle the subtleties; i.e:
def incoming_tasks
@user =current_user
@executed_tasks = @user.executed_tasks.where(completed_at: nil).order("created_at DESC")
end
def outgoing_tasks
@user = current_user
@assigned_tasks = @user.assigned_tasks.where(completed_at: nil).order("created_at DESC")
end
def completed_tasks
@user = current_user
@assigned_tasks = @user.assigned_tasks.where.not(completed_at: nil).order("completed_at DESC")
@executed_tasks = @user.executed_tasks.where.not(completed_at: nil).order("completed_at DESC")
end
As an aside, this would be a great place to use a scope.
Edit for detail:
(Caveat: SQL is a spec, not an implementation, and the SQL generated by rails depends on the database adapter. The following may vary depending on your choice of database.)
Ok, a few things:
You're using
where("completed_at = ?", 'nil')
, which is actually looking for records wherecompleted_at
is the string"nil"
. This is almost certainly not what you want, and has other unintended consequences.SQL has a very particular way of handling
NULL
values when it comes to matching rows. When using the=
operator in aWHERE
clause, it will ignore rows withNULL
values. You must use one of theIS NULL
orIS NOT NULL
operators to reason aboutNULL
values.
Consider the table:
| id | completed_at |
| 1 | 2015-07-11 23:23:19.259576 |
| 2 | NULL |
With the following queries:
Rails | SQL | Result
where("completed_at = ?", 'nil') | WHERE (completed_at = 'nil') | nothing, since completed_at isn't even a string
where.not("completed_at = ?", 'nil') | WHERE (NOT (completed_at = 'nil')) | only row 1, since = can't match a NULL value, even when negated
where("completed_at = ?", nil) | WHERE (completed_at = NULL) | nothing, you can't test for NULL with the = operator
where.not("completed_at = ?", nil) | WHERE (NOT (completed_at = NULL)) | nothing, you can't test for not NULL with = either
where(completed_at: nil) | WHERE completed_at IS NULL | row 2 only
where.not(completed_at: nil) | WHERE (completed_at IS NOT NULL) | row 1 only
Of course, where(completed_at: nil)
is just shorthand for where('completed_at IS NULL')
, and the same for its converse, but the hash format is more idiomatic and independent of the database adapter.
The magic part of all this is that ActiveRecord is able to figure out if it should use =
or IS NULL
by looking at the hash you pass to where
. If you pass a fragment, it has no idea, so it applies it blindly.
Related Topics
What MySQL Database Tables and Relationships Would Support a Q&A Survey With Conditional Questions
How to Turn Identity_Insert on and Off Using SQL Server 2008
Fastest Way to Remove Non-Numeric Characters from a Varchar in SQL Server
Rounding Off to Two Decimal Places in Sql
Simulate Create Database If Not Exists For Postgresql
Date Difference Between Consecutive Rows
How to Create Composite Primary Key in SQL Server 2008
Group by and Aggregate Sequential Numeric Values
Can a Table Field Contain a Hyphen
SQL - Subtracting a Depleting Value from Rows
MySQL: Split Comma Separated List into Multiple Rows
Constraint Defined Deferrable Initially Immediate Is Still Deferred
Difference Between Cte and Subquery
List of Special Characters For SQL Like Clause
MySQL Insert into Table Values.. VS Insert into Table Set