Ruby on Rails: Select from database where column equals a value from array - ruby-on-rails-3

If I have an array of IDs from a table (table1) in my database. Is there a way of querying another table (table2) to select all the records where a column equals a value equal to one of the IDs from table1.
My code so far is:
LabQuestion.where("product_id=#{Product.where(:brand_id => brand_id).pluck(:id)}")
In this code, I am trying to retrieve all the Lab Questions which are linked to all the products from a brand. This code does not work, but I've tried to demonstrate my needs.

Assuming you have setup your relations properly, you can use joins to join the two tables and query them like this:
LabQuestion.joins(:product).where(:products => { :brand_id => brand_id })

You can use includes instead of joins as below
LabQuestion.includes(:product).where(:products => { :brand_id => brand_id })

Related

How do I get pg-promise to return many rows in order?

I am using the following query in pg-promise:
SELECT id, title, price
FROM ${schema~}.ebooks
WHERE isbn = ${isbn};
pulling the data from pg with:
db.query(sql.ebooks.get, { isbn: isbn })
When I look at the row in pg they are in the order that I inserted them. The data does not have any ordering scheme (i cannot sort/order based on some column).
When using the query above, is it possible to get the data in the array to follow the row order in sequence?

Yii 1.1: Pk automatically added in SELECT for relations

I have some problems with the new version of SQL, which uses the only_full_group_by option. I have two tables: sensor and data. The sensor table HAS_MANY data, so the data table has a foreignkey to the pk of sensor table. Here is one relation:
'avg' => array(self::HAS_MANY, 'Data', 'sensor_id', 'select' => 'AVG(value) AS avg, date AS date', 'group' => 'date', 'order' => 'date desc')
Yii is complaining because there is a column in the SELECT statement that is not aggrgated. This column is the pk of the data table, which seems to be automatically added in the select of the generated query, in fact the query is:
SELECT AVG(value) AS avg, date as date, id_data FROM `data` `avg` WHERE ... GROUP BY date ORDER ...
What I want to do is to remove the added pk or wrap it with ANY_VALUE, so that the only_full_group_by option does not complain anymore.
Thank you
Found the answer by myself, writing it here to make it available to everyone.
To solve the problem you just need to add the id in the SELECT clause and give it the same alias given by the yii generate query. So, in my query I have
SELECT id as t0_c1 ...
I changed it to
SELECT ANY_VALUE(id) as t0_c1 ...

Using select statement in rails queries

I have three tables,
products has 3 columns, let them be
product_id,retailer_id,id
product_urls has 2 columns,
url_id,id
urls has 2 columns,
url_id, absolute_url
All the associations has been done in models.
Products & product_urls are joined on id = id (Products "has many" relationship with product_urls)
product_urls & urls are joined on Url_id = id (product_urls "belongs to" relationship with urls)
products & urls have "has many relationship"
I am trying to write a query, which selects A,B,C column from Table1 and X from Table3.
My query is:
Product.joins(:urls).select(:product_id,:retailer_id,:absolute_url).where(:id=>100, :urls => {:url_id=>100})
I am able to execute the query without any error, but I am not able to get data for X. when I check for sql query it is
select products.product_id, products.retailer_id, products.absolute_url ........ is executed.
Please help me how to fetch value from urls??
Try the below code
Product.joins(:urls).select("products.product_id,products.retailer_id,urls.abso‌​lute_url").where(:id=>100, :urls => {:url_id=>100})

Rails ActiveRecord query where relationship does not exist based on third attribute

I have an Adventure model, which is a join table between a Destination and a User (and has additional attributes such as zipcode and time_limit). I want to create a query that will return me all the Destinations where an Adventure between that Destination and the User currently trying to create an Adventure does not exist.
The way the app works when a User clicks to start a new Adventure it will create that Adventure with the user_id being that User's id and then runs a method to provide a random Destination, ex:
Adventure.create(user_id: current_user.id) (it is actually doing current_user.adventures.new ) but same thing
I have tried a few things from writing raw SQL queries to using .joins. Here are a few examples:
Destination.joins(:adventures).where.not('adventures.user_id != ?'), user.id)
Destination.joins('LEFT OUTER JOIN adventure ON destination.id = adventure.destination_id').where('adventure.user_id != ?', user.id)
The below should return all destinations that user has not yet visited in any of his adventures:
destinations = Destination.where('id NOT IN (SELECT destination_id FROM adventures WHERE user_id = ?)', user.id)
To select a random one append one of:
.all.sample
# or
.pluck(:id).sample
Depending on whether you want a full record or just id.
No need for joins, this should do:
Destination.where(['id not in ?', user.adventures.pluck(:destination_id)])
In your first attempt, I see the problem to be in the usage of equality operator with where.not. In your first attempt:
Destination.joins(:adventures).where.not('adventures.user_id != ?'), user.id)
you're doing where.not('adventures.user_id != ?'), user.id). I understand this is just the opposite of what you want, isn't it? Shouldn't you be calling it as where.not('adventures.user_id = ?', user.id), i.e. with an equals =?
I think the following query would work for the requirement:
Destination.joins(:adventures).where.not(adventures: { user_id: user.id })
The only problem I see in your second method is the usage of destinations and adventures table in both join and where conditions. The table names should be plural. The query should have been:
Destination
.joins('LEFT OUTER JOIN adventures on destinations.id = adventures.destination_id')
.where('adventures.user_id != ?', user.id)
ActiveRecord doesn't do join conditions but you can use your User destinations relation (eg a has_many :destinations, through: adventures) as a sub select which results in a WHERE NOT IN (SELECT...)
The query is pretty simple to express and doesn't require using sql string shenanigans, multiple queries or pulling back temporary sets of ids:
Destination.where.not(id: user.destinations)
If you want you can also chain the above realation with additional where terms, ordering and grouping clauses.
I solved this problem with a mix of this answer and this other answer and came out with:
destination = Destination.where
.not(id: Adventure.where(user: user)
.pluck(:destination_id)
)
.sample
The .not(id: Adventure.where(user: user).pluck(:destination_id)) part excludes destinations present in previous adventures of the user.
The .sample part will pick a random destination from the results.

Select distinct on id to return a row, but able to access other column values (rails association)

Ok so I'm doing an inner join on an association in rails like so:
#visits = #customer.visits.joins(:messages).select("distinct(visits.id)")
And this is returning unique visit id's however I want to loop through these visits, and access its associations (Each visit has a merchant_id attached to it as well). The problem with this inner join is that is is only returning the id so when I do something like this:
#visits.each do |v|
merchant = v.merchant
end
I just end up with a nil class.
How can I select "visits" based on a unique visit.id but also return all the other columns in that row? Group by?
All you are selecting is the id, that's correct. Since you want an object, you have two options. So what you really want is along the lines of:
Visit.where(:visit_id => #customers.visits.select("distinct(id)"))
This is equivalent to:
"SELECT * FROM VISITS WHERE VISITS.ID IN (SELECT DISTINCT(ID) FROM VISITS WHERE VISITS.CUSTOMER_ID IN ?)", <id_list>
I'm not sure where 'messages' factors in in your schema, but it's basically just a join in the above query. Sometimes it;s helpful to figure out the SQL, and work backwards to ActiveRecord syntax if you're having trouble.