I've been going over a tonne of StackOverflow articles trying to work out a particularly tricky Rails 3 join query to no avail - so I'm asking a new question!
I have a model called "User" which has_many "Checks" via a polymorphic association (the actual columns on Check are "target_type" and "target_id"). The Check has a string column called "type", which denotes the reason for the check. Something like this:
-----------------------------------------------------
id | target_type | target_id | type |
-----------------------------------------------------
1 User 1 type_1
2 User 2 type_2
I want to find all users who don't have a check associated with them with a set type - so it's a join and a count, I think.
So for instance, I want to be able to make a query to find all users who have no "type_1" checks, and it should return the user with id #2.
How would I go about doing this?
(I've been looking at all the stuff around counts and grouping (e.g. Rails has_many association count child rows) but nothing seems to quite match.)
Thanks!
You can try sth like:
class Merchant < ActiveRecord::Base
...
def self.non_fraudulent
includes(:fraud_checks).group("#{self.table_name}.id").having("SUM(CASE WHEN fraud_checks.type = 'fraudulent_ip' THEN 1 ELSE 0 END) = 0")
end
end
Related
I have a problem with extracting data with one query. My two models looks like that:
# school.rb
class School < ActiveRecord::Base
has_many :meetings
end
# meetings.rb
class Meeting < ActiveRecord::Base
belongs_to :school
belongs_to :user
# fields
# status: [accepted, not_accepted, finished]
en
I want to take every school where passed User has less than 2 meetings with status finished. I was trying something like this:
School.joins(:meetings).where(meetings: { user: User, status: 'finished' }).group(:id).having( 'count(meetings.id) < 2')
But it works if User has one finished meeting in each school. I wonder if it is possible to solve this with one query? Maybe some of you knows if it is possible to do this and how?
#Edit
An example for easier understanding of what I would like to receive:
School | User | Meeting
1. A | Adam | finished
2. A | Adam | accepted
3. A | Adam | finished
4. B | Adam | accepted
5. C | John | finished
6. D | - | -
7. E | John | finished
So I want to create query which will returns school B, C, D and E for user Adam
I think you need to reverse your thinking here: get the schools you want to EXCLUDE from the results instead of trying to add extra ones to your query. Something like this:
# Get schools with more than 1 meeting for the user
excluded_schools = School.joins(:meetings)
.where(meetings: { user: User, status: 'finished' })
.group(:id)
.having('count(meetings.id) > 1')
# Get ALL schools except for the ones you didn't want
filtered_schools = School.where.not(id: excluded_schools.select(:id))
Using select(:id) instead of pluck(:id) avoids triggering a new database query, so all of this should take just 1 database query when used inside a method. Of course in the console you'll have to nest these instead of storing in variables if you want to accomplish everything in 1 query.
I have two tables:
**Project**
id
description
outcome_id
**Outcome**
id
reference
description
I would like to count the number of occurrences an outcome_id grouped by outcome_id:
Project.group(:outcome_id).count(:outcome_id) #I think this is right
#returns {1=>1, 2=>3}
However, I would like to do a join so I can associate the outcome_id with the description of the outcome as well e.g.
Outcome ID Description Count
1 foobar 1
2 barfoo 3
How do I go about achieving this?
These are my models:
Outcome.rb
class Outcome < ActiveRecord::Base
has_many :projects
end
Project.rb
class Project < ActiveRecord::Base
belongs_to :outcome
end
Let's say I have a user. A user can have several favorite colors. Then I let users search for other users with certain favorite colors. How should I structure this table? Having a table with 20 columns for each color seems like a bad idea, but trying to do a string match on a single column also seems very messy.
Users
id name
1 Don
FavoriteColors
id user_id red green blue orange violet...
1 1 0 0 1 1 1
And the shortened models:
User
has_many :colors
FavoriteColor
belongs_to :user
take a look at 2.6 The has_and_belongs_to_many Association on here
The has_and_belongs_to_many Association
For many to many relations this would be the best approach because it is normalized.
OK, I recently had great answers to a question about how to do some sub-selects in an activerecord query. I now have a more complicated situation that I can't figure out.
I want to do a search across 3 tables that have a many-to-one relationship with a :through , eg
class User << ActiveRecord::Base
has_many :pets
has_many :parasites, :through => :pets
end
class Pet << ActiveRecord::Base
has_many :parasites
belongs_to :users
end
class Parasite << ActiveRecord::Base
belongs_to :pets
end
Now let's say I have some data like so
users
id name
1 Bob
2 Joe
3 Brian
pets
id user_id animal
1 1 cat
2 1 dog
3 2 cat
4 3 dog
parasites
id pet_id bug
1 1 tick
2 2 flea
3 3 tick
4 3 flea
5 4 tick
What I want to do is create an active record query that will return a user that has a pet which has both ticks and fleas (i.e. User 2 - Joe)
This is so far beyond my activerecord and sql skills that I won't even bother to show you my bungled attempts so far.
This is pretty much the same as the previous question, you only need to dig one level deeper on the sub-selects:
User.where('id IN (SELECT user_id FROM pets WHERE
id IN (SELECT pet_id FROM parasites WHERE bug = ?) AND
id IN (SELECT pet_id FROM parasites WHERE bug = ?))', 'flea', 'tick')
We have objects that we want to represent in stacks (think of stacking items in an MMO). There will be duplicate rows.
Let's say our owned_objects table looks like this.
user_id | object_id
1 | 27
1 | 27
3 | 46
3 | 46
5 | 59
I want the query to do
SELECT
user_id,
object_id,
count(*) AS count
FROM owned_objects
GROUP BY
user_id,
object_id;
And return either the 3 distinct OwnedObjects (or even just getting the distinct Objects would work too) and a count associated with it.
I know this is possible with SQLAlchemy, but can you do it with ActiveRecord?
How about …
#objects = user.objects.all(:select => "count(*) as count, objects.*", :group => :object_id)
… or similar?
You can then retrieve the counts by a dynamically created attribute on each object:
#object.first.count # the "stack depth" of the first object.
This assumes either a has_and_belongs_to_many :objects or a has_many :objects, :through => :owned_objects on user.
Found a solution, but not sure if it's the cleanest (hope it isn't).
Basically I created a SQL view that does that query and created a model for it. There's a plugin for rails that recognizes views on migrations.