I have а little question, write through Activerecord Query Interface
It's actually:
Gp.select("date('gps'.'created_at') as date,('users'.'name') as name, SUM('gps'.'sum_issue') as sum_issue").joins('LEFT JOIN users ON users.id = gps.user_id').where("users.ab_id = :abs_id AND users.id != 20", {:abs_id => current_user.ab_id}).group("users.name")
Result of query must be user name, sum,and date. If i do this query directly from SQLlite it's work, But
Active Record Query Interface give me
[#<Gp sum_issue: 289000>, #<Gp sum_issue: 364130>, #<Gp sum_issue: 620000>]
How i can get a name,date,sum_issue and show it in my helper.
like this:
{
created_at: datet,
sum_issue: sum_issue,
name: name
}
Try
Gp.select("date('gps'.'created_at') as date,('users'.'name') as name, SUM('gps'.'sum_issue') as sum_issue").joins('LEFT JOIN users ON users.id = gps.user_id').where("users.ab_id = :abs_id AND users.id != 20", {:abs_id => current_user.ab_id}).group("users.name").first.name
Related
I have a couple of models: User and UserTags
A User has_many UserTags
A UserTag belongs_to User
I am trying to find all the Users which don't have a UserTag with name 'recorded' (so I also want users which don't have any tags at all). Given a users relation, I have this:
users.joins("LEFT OUTER JOIN user_tags ON user_tags.user_id = users.id AND user_tags.name = 'recorded'").
where(user_tags: { id: nil })
Is there any other better or more Railsy way of doing this?
Try this:
users.joins("LEFT OUTER JOIN user_tags ON user_tags.user_id=users.id").where("user_tags.name != ? OR user_tags.id is NULL", 'recorded')
This one should work:
users.joins(:user_tags).where.not(user_tags: { name: 'recorded' })
Joins not eager load nested model you should use "Includes or eage_load"
users.eager_load(:user_tags).where.not(user_tags: { name: 'recorded' })
This will use left outer join and you can update your query in where clause.
Same as
users.includes(:user_tags).where.not(user_tags: { name: 'recorded' })
Try this, It will return the users with 0 user_tags :
users = users.joins(:user_tag).where("users.id IN (?) OR user_tags.name != ?",User.joins(:user_tag).group("users.id").having('count("user_tag.user_id") = 0'), "recorded")
Hey you can simply use includes for outer join as user_tags.id is null returns all your record not having user_tags and user_tags.name != 'recorded' returns record having user_tag name is not recorded
users.includes(:user_tags).where("user_tags.id is null or user_tags.name != ?","recorded")
Or you can also used using not in clause as but it is not optimised way for given query:
users.includes(:user_tags).where("users.id not in (select user_id from user_tags) or user_tags.name != ?","recorded")
I'm using a find_by_sql method to search users in my userstable.
is there a possibility to use rails code in the select statement?
User.find_by_sql ["SELECT DISTINCT
users.*
FROM
users
JOIN
clients_courses cc
ON
cc.client_id = users.client_id
LEFT JOIN
memberships m
ON
m.user_id = users.id AND m.course_id = cc.course_id
WHERE
cc.course_id = ?
AND
m.user_id IS NULL
AND
users.active = ?
AND
users.firstname LIKE ? or users.lastname LIKE ?
AND NOT IN ( RAILS CODE )", self.id, true, "#{search}%", "#{search}%"]
end
I Marked the position with RAILS CODE
I want to do someting linke this:
Membership.where("course_id = ?", self.id).users
is there a way to do this?
You can do this -
member_user_ids = []
Membership.where("course_id = ?", self.id).map{|membership| membership.users.map{|user| member_user_ids << user.id}}
# you might want to put a uniq! on member_user_ids
User.find_by_sql ["SELECT DISTINCT
users.*
FROM
users
JOIN
clients_courses cc
ON
cc.client_id = users.client_id
LEFT JOIN
memberships m
ON
m.user_id = users.id AND m.course_id = cc.course_id
WHERE
cc.course_id = ?
AND
m.user_id IS NULL
AND
users.active = ?
AND
users.firstname LIKE ? or users.lastname LIKE ?
AND users.id NOT IN ( #{member_user_ids.join(',')} )", self.id, true, "#{search}%", "#{search}%"]
You can also have a look at link which explains how to put array of strings in where clause.
I have inherited another programmer's Rails3 project, and I'm fairly new to rails overall. He's got a query that appears to sort by specific id's. Can somebody explain how this resolves in actual SQL? I think this code is killing the db and subsequently rails. I've tried to output it in the logger but can't seem to get the actual SQL to output even with config set to :debug. Searching heavily here (on SO) didn't turn up a clear explanation of how this query looks. The code looks like:
options = {
select: "SUM(1) AS num_demos, product_id ",
group: "product_id",
order: "num_demos ASC",
}
product_ids = Demo.where("state = 'waitlisted'").find(:all, options).collect{|d| d.product_id}
sort_product_ids = product_ids.collect{|product_id| "id = #{product_id}"}
Product.where(visible: true, id: product_ids).order(sort_product_ids.join(', '))
As far as I can see, the final line will create a query against the product table with an ORDER BY "id = 1, id = 3, ..." etc, which doesn't make a lot of sense to me. All clues appreciated.
A quick breakdown of what's going on, as it'll help you understand what to do for your replacement query.
options = {
select: "SUM(1) AS num_demos, product_id ",
group: "product_id",
order: "num_demos ASC",
}
product_ids = Demo.where("state = 'waitlisted'").find(:all, options).collect{|d| d.product_id}
This line will generate
SELECT SUM(1) as num_demos, product_id FROM "demos" WHERE (state = 'waitlisted') GROUP BY product_id
And returns an array of Demo objects, sorted by the count(*) of rows in the group, where only the product_id attribute has been loaded, and is available to you.
Next,
sort_product_ids = product_ids.collect{|product_id| "id = #{product_id}"}
results in a collection of product_ids mapped to the format "id = x". IE: If the previous result returned 10 results, with product_ids ranging from 1..10, sort_product_ids is now equivalent to ["id = 1", "id = 2", "id = 3", "id = 4", "id = 5", "id = 6", "id = 7", "id = 8", "id = 9", "id = 10"]
Finally,
Product.where(visible: true, id: product_ids).order(sort_product_ids.join(', '))
Selects all Products where the column visible is true, and their id is in the array of product_ids (which, as we found out earlier, is actually an array of Demo objects, not integers - this might be causing the query to fail). Then, it asks SQL to sort that result list by the sort_product_ids (sent in as a string "id = 1, id = 2, ... id = 10" instead of an array ["id = 1", "id = 2", ... "id = 10"]).
More info available at:
http://guides.rubyonrails.org/active_record_querying.html
http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html
To select and sort by a given array of ids you can use this
Product.where(visible: true, id: product_ids)
.order( "field(id,#{product_ids.join(',')})" )
If you are using PostgreSQL, consider to use WITH ORDINALITY, it is the fastest way compared to others. See this thread.
To apply this method to Ruby on Rails, for example:
class SpecifiedByIds
def specified_by_ids(ids)
joins(
<<~SQL
LEFT JOIN unnest(array[#{ids.join(',')}])
WITH ORDINALITY AS t(id,odr) ON t.id = #{table_name}.id
SQL
).order('t.odr')
end
end
class MyModel < ActiveRecord::Base
extend SpecifiedByIds
end
I have an sql query like this:-
SELECT * FROM `permissions` join entities where NOT EXISTS (select
entity_id,permission_id from role_permissions where role_id=5 and
entities.id = role_permissions.entity_id and permissions.id =
role_permissions.permission_id)
I would like to get the corresponding rails query.
I have tried this.
Permission.joins("join entities").joins("LEFT OUTER JOIN role_permissions on
permission_id != permissions.id and entities.id != entity_id and
role_permissions.role_id= role_id").select("role_permissions.entity_id,role_permissions.role_id,
role_permissions.permission_id").group('role_permissions.entity_id,
role_permissions.permission_id')
But it doesn't works.
thanks
hari
I have been particularly in love with EXISTS queries lately, precisely because it does not require you to fully join another table. As far as I know, you do have to explicitly write the SQL clause, but you can still make it work with Activerecord. You can even put this in a scope within a lambda block.
Permission.joins(:entities).where(<<-SQL
NOT EXISTS(
select
* from role_permissions where role_id=#{your_role_id} and
entities.id = role_permissions.entity_id
and permissions.id = role_permissions.permission_id
)
SQL
)
Try like this for a default SQL query:
sql = "SELECT some_field FROM `permissions` join entities where NOT EXISTS (select entity_id,permission_id from role_permissions where role_id=5 and entities.id = role_permissions.entity_id and permissions.id = role_permissions.permission_id)"
results = ActiveRecord::Base.connection.execute(sql)
results.each do |result|
#register_users << { some_field: result[0] }
end
Try this
UPDATED BASED ON FIRST COMMENT
Permission.joins(:entities).joins("LEFT OUTER JOIN role_permissions on
permission_id != permissions.id and entities.id != entity_id and
role_permissions.role_id= role_id")
.select("role_permissions.entity_id,role_permissions.role_id,
role_permissions.permission_id")
.group('role_permissions.entity_id, role_permissions.permission_id')
I am performing a join query with rails with a select however, the result has null id's for the joined table...
#result = Table.joins(:join_table).select(['join_table.id', 'name', 'random_attr', 'created_at']).where('table.random_attr = ?', #anotherresult.id).order('name ASC')
The result...
[
{
random_attr: true
created_at: "2012-10-31T02:23:07Z"
id: null
name: "Joe"
},
....
]
The produced sql looks like...
SELECT join_table.id, name, random_attr, created_at FROM `table` INNER JOIN `join_table` ON `join_table`.`id` = `table`.`user_id` WHERE (random_attr = 9) ORDER BY name ASC;
Doing this query directly in mysql works fine.