Here's my stat model.
Stat(id: integer, points: float, user_id: integer, match_id: integer, team_id: integer)
For team model
Team(id: integer, name: string)
I'm getting error on teams.name part here's the error.
#<ActiveRecord::StatementInvalid: Mysql2::Error: Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'db-name.teams.name' which is not functionally dependent on columns in GROUP BY clause;
Sample stat:
{id: 1, points: 2, user_id: 1, match_id: 1, team_id: 1}
{id: 2, points: 3, user_id: 3, match_id: 1, team_id: 2}
{id: 3, points: 4, user_id: 1, match_id: 2, team_id: 1}
My current code:
sample = Stat
.joins(:user)
.joins(:team)
.select('teams.name as team_name, users.id as user_id, match_id, SUM(points) as points')
.where(user_id: params[:user_id])
.group(:match_id)
.where.not(match_id: nil)
.order("match_id DESC")
.limit(10)
Related
[#<ActiveRecord::Associations::CollectionProxy [#<InvoiceServiceType id: 1, value_charged: 50.0, invoice_id: 4, service_type_id: 1>, #<InvoiceServiceType id: 2, value_charged: 50.4, invoice_id: 4, service_type_id: 2>]>, #<ActiveRecord::Associations::CollectionProxy [#<InvoiceServiceType id: 8, value_charged: 70.0, invoice_id: 1, service_type_id: 2>, #<InvoiceServiceType id: 9, value_charged: 50.0, invoice_id: 1, service_type_id: 6>]>]
I want to sum all value_charged .
im try map(&:value_charged).sum
collect..
and nothing :(
Thank you
Lets say that you have a #object with a has_many relationship details, and details have a field call :value_charged, you could try sum all the :value_charged of #object.details with:
#object.details.sum(:value_charged)
An array of records being generated by
#signatures = Signature.where('action_id IN (?)', #actions).all
will have actions with one or more signatures.
Signature id: 1, action_id: 1
Signature id: 2, action_id: 2
Signature id: 3, action_id: 1
Signature id: 4, action_id: 3
Signature id: 5, action_id: 2
What ruby instruction can extract just the single cases, based on action_id? Signature.id = 4 in the above example
#signatures = Signature.where(action_id: #actions)
.group('action_id')
.select('id, count(action_id)')
.having('count(action_id) = 1')
I have table with some columns: id, user_id, message_id, message_type; for example:
id: 1, user_id: 1, message_id: 4, message_type: 'Warning'
id: 2, user_id: 1, message_id: 5, message_type: 'Warning'
id: 3, user_id: 1, message_id: 6, message_type: 'Warning'
id: 4, user_id: 2, message_id: 4, message_type: 'Error'
id: 5, user_id: 2, message_id: 1, message_type: 'Exception'
id: 6, user_id: 1, message_id: 2, message_type: 'Exception'
id: 7, user_id: 1, message_id: 3, message_type: 'Exception'
id: 8, user_id: 2, message_id: 4, message_type: 'Exception'
I want to get grouping result like news in social networks. On columns user_id and message_type, while message_type repeating. And need LIMIT 20 ORDER BY id DESC.
Example:
id: 8, user_id: 2, message_id: 4, message_type: 'Exception'
id: {6,7} user_id: 1, message_id: {2,3}, message_type: 'Exception'
id: 5, user_id: 2, message_id: 1, message_type: 'Exception'
id: 4, user_id: 2, message_id: 4, message_type: 'Error'
id: {1, 2, 3}, user_id: 1, message_id: {4, 5, 6}, message_type: 'Warning'
How to do it with best performance?
I found only 1 way:
With window function lead() find a moment when was changed dict (user, message type)
With window function sum() set sequnce number for each new dict
Group by sequence and select what you need:
Checking:
create table test (
id serial primary key,
user_id integer,
message_id integer,
message_type varchar
);
insert into test (user_id, message_id, message_type)
values
(1, 4, 'Warning'),
(1, 5, 'Warning'),
(1, 6, 'Warning'),
(2, 4, 'Error'),
(2, 1, 'Exception'),
(1, 2, 'Exception'),
(1, 3, 'Exception'),
(2, 4, 'Exception')
;
select
array_agg(grouped.id) as record_ids,
grouped.user_id,
array_agg(grouped.message_id) as message_ids,
grouped.message_type
from (
select changed.*,
sum(changed.changed) over (order by changed.id desc) as group_n
from (
select tt.*,
case when lag((user_id, message_type)) over (order by tt.id desc) is distinct from (user_id, message_type) then 1 else 0 end as changed
from test tt
) changed
order by id desc
) grouped
group by grouped.group_n, grouped.user_id, grouped.message_type
order by grouped.group_n
;
Result:
record_ids | user_id | message_ids | message_type
------------+---------+-------------+--------------
{8} | 2 | {4} | Exception
{7,6} | 1 | {3,2} | Exception
{5} | 2 | {1} | Exception
{4} | 2 | {4} | Error
{3,2,1} | 1 | {6,5,4} | Warning
(5 rows)
The array_agg function should do the trick:
SELECT user_id,
message_type,
ARRAY_AGG (DISTINCT id),
ARRAY_AGG (DISTINCT message_id)
FROM mytable
GROUP BY user_id, message_type
I am using Mongoid, Rails and Fabrications and at a total loss with how this is happening. Any thoughts very appreciated, but I know this pretty complicated. I just want to fabricate a user and have only four joined groups, but I keep getting eight loaded.
Here is the relevant section of my code
#user1 = Fabricate.build(:registered)
#user1.joined_groups << [common_group,
cali_group,
ca46,
Fabricate(:polco_group, {:name => "Gang of 13", :type => :custom})]
When I run #user1.joined_groups.size I get 4, but when I do #user1.joined_groups.map(&:name), I get 8 records:
#<PolcoGroup _id: 1 ... member_ids: [], follower_ids: []>
#<PolcoGroup _id: 1 ... member_ids: [], follower_ids: []>
#<PolcoGroup _id: 1 ... member_ids: [], follower_ids: []>
#<PolcoGroup _id: 1 ... member_ids: [], follower_ids: []>
#<PolcoGroup _id: 1 ... member_ids: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], follower_ids: [1, 1]>
#<PolcoGroup _id: 1 ... member_ids: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], follower_ids: [1, 1]>
#<PolcoGroup _id: 1 ... member_ids: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], follower_ids: [1, 1]>
#<PolcoGroup _id: 1 ... member_ids: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], follower_ids: [1, 1]>
(where i have replaced all BSON::ObjectId('4eab3ca5f11aac2701000009') statements with ones and removed a lot of the middle code.
The full set of code is available here: https://gist.github.com/1323984
Most bizzarre simply calling map might be causing the problem.
puts "just created user with these groups:"
puts #user1.joined_groups.map(&:name)
puts "then secondly"
puts #user1.joined_groups.map(&:name)
Generates this (!):
just created user with these groups:
Dan Cole
CA
CA46
Gang of 13
then secondly
Dan Cole
CA
CA46
Gang of 13
Dan Cole
CA
CA46
Gang of 13
Thanks for any insight! After repeated attempts, I can't figure out a way in terminal to duplicate this, so I am suspecting the Fabrication gem. (Update: nope, I get this error with standard mongoid objects, so I am totally blaming mongoid.)
Tim
I think the problem might simply be that you are not pushing the groups onto the user correctly. Try using concat or separately shoveling them.
#user1.joined_groups.concat([common_group,
cali_group,
ca46,
Fabricate(:polco_group, {:name => "Gang of 13", :type => :custom})])
>> c = Course.find(3).course_steps.order(:position)
=> [#<CourseStep id: 9, step_id: 4, course_id: 3, position: 1, created_at: "2011-03-08 20:57:44", updated_at: "2011-03-08 20:57:44">, #<CourseStep id: 10, step_id: 5, course_id: 3, position: 2, created_at: "2011-03-08 20:57:45", updated_at: "2011-03-08 20:57:45">, #<CourseStep id: 8, step_id: 2, course_id: 3, position: 3, created_at: "2011-03-08 20:57:42", updated_at: "2011-03-08 20:57:42">]
I need to find a course_step that is after id 9 (which happens to be course_step with id 10) (if it is exists)
I also need to find the previous (if it is exists)
I know I could manually do it be looping through the results, but I would rather do it with SQL.
The NEXT sql query would be:
SELECT * FROM course_steps WHERE position >=POSITION_OF_STEP ORDER BY position LIMIT 1 OFFSET 1
The PREVIOUS sql query would be:
SELECT * FROM course_steps WHERE position <= POSITION_OF_STEP ORDER BY position DESC LIMIT 1 OFFSET 1
I think I got it!
class CourseStep < ActiveRecord::Base
belongs_to :step
belongs_to :course
validates_uniqueness_of :step_id, :scope => :course_id
def next_step()
Course.find(self.course.id).course_steps.order(:position).where("position >= ?", self.position).limit(1).offset(1).first
end
def previous_step()
Course.find(self.course.id).course_steps.order("position DESC").where("position <= ?", self.position).limit(1).offset(1).first
end
end