Connecting Id field with name field - ruby-on-rails

Am having a table with quetion_id , nominees and vote_count. In which the values for question_id and nominees are prepopulated from other tables with vote_count as zero.
If the users select some nominees the vote count should be incresed by one. The problem is How to connect the question_id and nominees like for this question_id this nominee is selected .
can some one give example for this situation..

I'll answer based on this scenario:
So you have a...
1) User
who can...
2) Vote
for a...
3) Nominee
And it's a given that MANY users can vote for MANY nominees.
You probably aready have tblUser and tblNominee - so you need a link table that can contain the votes (tblUserNomineeVote).
tblUserNomineeVote has fields for UserId and NomineeId, and therefore registers a vote. You may need to add constraints depending on how many votes a user can register etc.
You can then use:
SELECT
tblNominee.Name,
COUNT(*)
FROM
tblNominee
INNER JOIN
tblUserNomineeVote ON tblUserNomnieeVote.NomineeId = tblNominee.NomineeId
GROUP BY
tblNominee.Name

Related

rails activerecord - distinct counter cache implementation

I have these tables:
broadcast
id
name
email
id
broadcast_id
user_id
subject
email_open
id
email_id
user_id
I want to keep a count of the email_open records in my broadcast table.
Is the most efficient way of doing this by having a broadcast_id in my email_open table? If it is.. then I know I can just do this in my email_open model:
belongs_to :broadcast, counter_cache: => true
Then, I add a email_open_count to my broadcast table... but I'm wondering if there's a way to do it without doing this.
Also, multiple users can have repeated records in email_open.. how do I make the count be of distinct user_id?
For example, user_id 1 can open an email 5 times but I just want the email_open_count to be 1.
Thanks
So as per your example, if user_id 1 can open an email 5 times but You just want the email_open_count to be 1.You can the same user_id to email or whichever table you want only if that user opens an email but if the user has already open don't save it again.

Retrive records which are not referenced in other table, ActiveRecord query

There are 2 tables : User and Teacher. Teacher.user_id is from User. So, how do I find in a single query, all the users who are not in teachers.
I meant something along the lines :
User.not_in(Teacher.all)
You can use where.not query from ActiveRecord try something like below:
User.where.not(id: Teacher.pluck(:user_id).reject {|x| x.nil?})
Note: used reject method, in case you have nil values in some records.
The other users seem to have neglected the rails 3 tag (since removed based on the approved answer. My answer left for posterity) : Please try this
User.where("id NOT IN (?)",Teacher.pluck(:user_id).join(","))
This will become SELECT * FROM users WHERE id NOT IN (....) (two queries one to get the user_id from teachers and another to get the user(s) not in that list) and may fail based on the size of teacher table.
Other option is an arel table:
users = User.arel_table
User.where(users[:id].not_in(Teacher.select(:user_id).where("user_id IS NOT NULL")))
This should produce a single query similar to
SELECT * FROM users
WHERE id NOT IN ( SELECT user_id FROM teachers WHERE user_id IS NOT NULL)
(one query better performance) * syntax was not fully tested
Another single query option might be
User.joins("LEFT OUTER JOIN teachers ON teachers.user_id = users.id").
where("teachers.user_id IS NULL")
I think you should be able to do something like this
User.where.not(id: Teacher.ids)

How to get unique product list?

We have list of category products having duplicate names.
How to get a list of products which should not have duplicate product name in Postgres?
We are searching for min product ids with group by name.
then searching the products in ids.
category = Category.first
ids = Product.select("MIN(id) as id").where(deleted: false).group(:name).collect(&:id)
category.products.where("products.id IN (?)", ids).find_active
How can we optimize the queries?
You can do Product.all.pluck(:name).uniq to get just the product names in an array.
But I think you're solving the wrong problem, in that this problem has a bad 'smell'. If you have products that have identical names, how do you differentiate them from a UX perspective? And why only get the first created product by that name vs. the most 'popular' product? I'm trying to imagine how this solution would work for the user and I'm coming up blank, perhaps because I don't know enough about the context.
Edit: Also, could you clarify what you mean by 'should not have duplicate product name'? Is it to get a list of products, but only the first product if there's multiple products with the same name? Or are you looking for items to correct?
The simple solution in Postgres is with DISTINCT ON:
SELECT DISTINCT ON (name)
id, name -- add more columns if you need
FROM Product
WHERE deleted = FALSE
ORDER BY name, id;
Returns unique product names (sorted alphabetically). From each set of dupes the one with the smallest id. Details:
Select first row in each GROUP BY group?

Compare 3 tables in SQLite

Originally, I have 2 tables. I normalized it since the relationship of this tables is many to many. Now I have 3.
Jobs
jID PK
jName
jDesc
jEarnings
jTags
Course
cID PK
cName
cDesc
cSchool
cProgram
JobsCourse
ID PK
jID FK
cID FK
My app displays a tableview of the jobs
When clicked it displays the UIViewcontroller of jobs plus a tableview of the related course
How do I query the jobcourse table so that I can get all the related Courses to a certain job?
You can join the two tables, e.g.:
SELECT course.* FROM course INNER JOIN jobscourse ON jobscourse.cID = course.cID WHERE jobscourse.jID = ?
That gets all entries from course where the jID in jobscourse is equal to some value.

Ranking position

I have a Rails application with the following models:
User
Bet
User has many_bets and Bets belongs_to User. Every Bet has a Profitloss value, which states how much the User has won/lost on that Bet.
So to calculate how much a specific User has won overall I cycle through his bets in the following way:
User.bets.sum(:profitloss)
I would like to show the User his ranking compared to all the other Users, which could look something like this:
"Your overall ranking: 37th place"
To do so I need to sum up the overall winnings per User, and find out in which position the current user is.
How do I do that and how to do it, so it don't overload the server :)
Thanks!
You can try something similar to
User.join(:bets).
select("users.id, sum(bets.profitloss) as accumulated").
group("users.id").
order("accumulated DESC")
and then search in the resulting list of "users" (not real users, they have only two meaningful attributes, their ID and a accumulated attribute with the sum), for the one corresponding to the current one.
In any case to get a single user's position, you have to calculate all users' accumulated, but at least this is only one query. Even better, you can store in the user model the accumulated value, and query just it for ranking.
If you have a large number of Users and Bets, you won't be able to compute and sort the global profitloss of each user "on demand", so I suggest that you use a rake task that you schedule regularly (once a day, every hour, etc...)
Add a column position in the User model, get the list of all Users, compute their global profitloss, sort the list of Users with their profitloss, and finally update the position attribute of each User with their position in the list.
Best way to do it is to keep a pre calculated total in your database either on user model itself or on a separate model that has 1:1 relation to user. If you don't do this, you will have to calculate sum for all users at all times in order to get their rating, which means full table operation on bets table. This said, this query will give you desired results, if more than 1 person has the same total, it will count both as rating X:
select id, (select count(h.id) from users u inner join
(select user_id, sum(profitloss) as `total` from bets group by user_id) b2
on b2.user_id = u.id, (select id from users) h inner join
(select user_id, sum(profitloss) as `total` from bets group by user_id) b
on b.user_id = h.id where u.id = 1 and (b.total > b2.total))
as `rating` from users where id = 1;
You will need to plug user.id into query in where id = X
if you add a column to user table to keep track of their total, query is a little simpler, in this example column name is total_profit_loss:
select id, total_profit_loss, (select count(h.username)+1 from users u,
(select username, score from users) h
where id = 1 and (h.total_profit_loss > u.total_profit_loss))
as `rating` from users where id = 1;

Resources