I am using rails 4 for developing my application. I have a problem in my active record query with not equal to condition. I am not getting required output. I think there is a problem with not equal to part.
#available_rooms = Room.joins("LEFT OUTER JOIN reservations ON reservations.room_id = rooms.id").where("category_id = ? AND arrival_date != ?",params[:category],params[:arrival_date])
You can use where.not() in Rails 4 :
#available_rooms = Room.joins("LEFT OUTER JOIN reservations ON reservations.room_id = rooms.id")
.where(category_id: params[:category])
.where.not(arrival_date: params[:arrival_date])
In some version of SQL not equal is written as !=
Try this using the comparator <> like so:
#available_rooms = Room.joins("LEFT OUTER JOIN reservations ON reservations.room_id = rooms.id")
.where("category_id = ? AND arrival_date <> ?",params[:category],params[:arrival_date])
Related
I have this relation:
class Action < ApplicationRecord
has_many :actions_users
I tried to make a query like:
select *
from actions left outer join actions_users
on actions_users.action_id = actions.id and actions_users.user_id = 1
where actions.user_id = 1
Meanwhile, in my experience, in all of the result that I tried,
select *
from actions left outer join actions_users
on actions_users.action_id = actions.id
where actions.user_id = 1 and actions_users.user_id = 1
the join condition code and general condition are in where function.
How can I work it out?
You can pass a string in join query and use the rails table naming conventions for this.
Action.joins("left outer join action_users on (action_users.id = actions.id and action_users.id = 1")).where('action_users.user_id = ? ', 1)
Because you have a general where condition, you can use includes. This will generate a LEFT OUTER JOIN query:
Action.includes(:actions_users).where(actions_users: { user_id: true })
Or if you are using Rails 5+, Active Record provides a finder method left_outer_joins:
Action.left_outer_joins(:actions_users).where(actions_users: { user_id: true })
Action.left_outer_joins(:actions_users).where(user_id: 1)
select *
from actions left outer join actions_users
on actions_users.action_id = actions.id and actions_users.user_id = 1
where actions.user_id = 1
Although you did not ask for it yet, ...
Action.left_outer_joins(:actions_users).where(actions_users: {status: 'active'})
select *
from actions left outer join actions_users
on actions_users.action_id = actions.id and actions_users.user_id = 1
where actions_users.status = 'active'
Up to Rails 7 there is no way to specify conditions directly on an OUTER JOIN, see the documentation for Specifying Conditions on the Joined Tables. The examples shown are suitable for INNER JOINs (as they use .where), but won't work for OUTER JOINs for the same reason.
You could try to specify the OUTER JOIN manually, but will run into problems passing parameters:
Action.joins("LEFT OUTER JOIN action_users ON (action_users.id = actions.id AND action_users.id = :user_id")
So you will need to do parameter substitution somewhat like this:
outer_join_sanitized = ApplicationRecord.sanitize_sql([
"LEFT OUTER JOIN action_users ON (action_users.id = actions.id AND action_users.id = :user_id)",
{ user_id: 22 }
])
And you could then use Actions.joins(outer_join_sanitized). At this point you might agree that just running with raw SQL from the start is the easier way to go.
SELECT A.FirstName, A.LastName, B.PatientId, B.RoomNumber, B.AdmissionDate, B.DischargeDate, B.MeasureCategory
FROM DimPatient A, DimPatientStay B
WHERE A.Id = B.PatientId AND A.FirstName = 'Anuj' AND B.MeasureCategory = 'ED'
hi some updation for this
i solved this prob by
MODELNAME.find_by_sql("your sql query")
You can try this to find the result from sql query in Rails
query_params = Hash.new
sql_query = "SELECT A.FirstName, A.LastName, B.PatientId, B.RoomNumber, B.AdmissionDate, B.DischargeDate, B.MeasureCategory
FROM DimPatient A, DimPatientStay B
WHERE A.Id = B.PatientId AND A.FirstName = :first_name AND B.MeasureCategory = :measure_category"
query_params[:first_name] = first_name
query_params[:measure_category] = measure_category
#query_results = ActiveRecord::Base.connection.select_all(
ActiveRecord::Base.send("sanitize_sql_array",[sql_query, query_params] )
)
I guess you could try:
ActiveRecord::Base.connection().execute(#your_sql_here)
Suppose A is one class and B is another, you should use includes as following:
A.includes(:b).where(...) # add you condition in where
I suggest to check good video tutorials of ActiveRecord here
Why does ActiveRecord always return -1 whether it's through a browser or through the console?
SQL statement:
SELECT category.categoryname, sum(lineitems.qty) as totalSales,
sum(lineitems.qty*size.sizeship) as volume,
sum(lineitems.qty*lineitems.purcprice) AS totmerchandise FROM category, products,
orders, shipments, lineitems, size WHERE
category.categoryid = products.categoryid AND products.productid =
lineitems.productid AND lineitems.posshipid = shipments.posshipid AND
shipments.posorderid = orders.posorderid AND size.sizeid = products.size AND
category.categoryid NOT IN (77,79) AND orders.orderstatus in
(1,4,5) AND orders.ordercomplete = 1 AND numbotincase > 0 AND orders.date >=
'20130501' AND orders.date < '20130531' GROUP BY
category.categoryname ORDER BY category.categoryname`
When I execute this in Microsoft SQL server, it loads a bunch of records.
However, in Rails when I try to do this:
query_for_category_bottles_volume_totalsales = "SELECT category.categoryname,
sum(lineitems.qty) as totalSales, sum(lineitems.qty*size.sizeship) as volume,
sum(lineitems.qty*lineitems.purcprice) AS totmerchandise FROM category, products,
orders, shipments, lineitems, size WHERE category.categoryid = products.categoryid
AND products.productid = lineitems.productid AND lineitems.posshipid =
shipments.posshipid AND shipments.posorderid = orders.posorderid AND
size.sizeid = products.size AND category.categoryid NOT IN (77,79) AND
orders.orderstatus in (1,4,5) AND orders.ordercomplete = 1 AND numbotincase > 0
AND orders.date >= '20130501' AND orders.date < '20130531' GROUP BY
category.categoryname ORDER BY category.categoryname"
category_bottles_volume_totalsales = ActiveRecord::Base.connection.execute(query_for_category_bottles_volume_totalsales)
This happens not only for this query, but something simple like this as well: ActiveRecord::Base.connection.execute("select * from orders where id = 987;"). However, in the console when I do Order.find(987) it returns a record.
So the solution was to change the way ActiveRecord was making the query.
database = ActiveRecord::Base.connection
query_for_category_bottle_casecost_case_price = "SELECT ..."
category_bottle_casecost_case_price = database.select_all(query_for_category_bottle_casecost_case_price)
This must be a basic thing in rails, but I don't know how to do it.
I would like to filter participants based on the languages they speak. People can speak multiple languages, and languages are stored in their own table with a one-to-many relationship.
Now my search looks really clunky and doesn't seem to work:
if #cvsearch.language.present? == true and #cvsearch.language != 0
#p = #p.joins(:languages).where('languages.name = ?', #cvsearch.language)
else
#cvsearch.language = 0
end
if #cvsearch.language1.present? == true and #cvsearch.language1 != 0
#p = #p.joins(:languages).where('languages.name = ?', #cvsearch.language1)
end
if #cvsearch.language2.present? == true and #cvsearch.language2 != 0
#p = #p.joins(:languages).where('languages.name = ?', #cvsearch.language2)
end
if #cvsearch.language3.present? == true and #cvsearch.language3 != 0
#p = #p.joins(:languages).where('languages.name = ?', #cvsearch.language3)
end
The resulting SQL, slightly shortened:
SELECT COUNT(*) FROM "participants" INNER JOIN "languages" ON "languages"."participant_id" = "participants"."id" WHERE (participants.id >= 2) AND (languages.name = 11) AND (languages.name = 10)[0m
It would be great to get a specific solution, but even better is a pointer as to where I can read up on this - what's the key word I am missing to describe this problem?
So this is the solution I am using for now:
if #cvsearch.language1.present? == true and #cvsearch.language1 != 0
safe_lang = ActiveRecord::Base::sanitize(#cvsearch.language1)
qry = "INNER JOIN languages l1 ON l1.participant_id = participants.id AND l1.name = " + safe_lang.to_s
#p = #p.joins(qry)
end
Works wonderfully, just need to get some feedback regarding the safety of this approach.
I'm not sure of a general reference to refer you to, but this is basic SQL stuff. Basically, the JOIN is performed first resulting in a number of rows and then the WHERE is applied, filtering the rows. The conceptual mistake here is thinking that the WHERE clause will somehow apply to the full set of matched languages, but it doesn't work that way, each row of the result is considered in isolation, therefore a clause like (languages.name = 11) AND (languages.name = 10) will never return anything, because languages.name only has a single value in each row. The query as constructed could only work for an OR clause, so you could say something like WHERE (languages.name = 11) OR (languages.name = 12).
In order to filter down the participants you need one join for each language, so you want something like this:
SELECT COUNT(*) FROM participants
INNER JOIN languages l1 ON l1.participant_id = participants.id AND (languages.name = 10)
INNER JOIN languages l2 ON l2.participant_id = participants.id AND (languages.name = 11)
WHERE participants.id >= 2
Offhand I'm not sure of the easiest way to do this in ActiveRecord, it's not a super common query. Your general structure should work, but with something like:
if #cvsearch.language1.present? == true and #cvsearch.language1 != 0
safe_language = ActiveRecord::Base.sanitize(#cvssearch.language1)
join_clause = "INNER JOIN languages l1 ON l1.participant_id = participants.id AND language.name = #{safe_language}"
#p = #p.joins(join_clause)
end
How should I write this with ActiveRecord:
select stores.id, stores.name, store_specials.active
from stores
left outer join store_specials on
(store_specials.store_id = stores.id and store_specials.special_id = 1)
where stores.active = true;
Thanks
Rails 3.x
Stores.select("stores.id, stores.name, store_specials.active").joins("LEFT OUTER JOIN tore_specials ON store_specials.store_id = stores.id AND store_specials.special_id = 1).where("store_specials.active = true")
Hopefully this is what you need