Ruby on rails convert to sql query - sql

I have did the first one, and want to check if I got it right or not? also I have no idea how to do number 2
Ruby ORM
Consider the following two active record definitions over the tables “customers” and “orders”. The orders table has a foreign key “cust_key” that references the primary key of “customers”, which is also named “cust_key”.
Table:
customers-
cust_key
address
orders-
order key
cust_key
order_priority
total_price
1 class Customer < ActiveRecord::Base
2 set_table_name "customers"
3 set_primary_key "cust_key"
4 has_many :orders, :foreign_key => "cust_key”
5 End
1 class Order < ActiveRecord::Base
2 set_table_name "orders"
3 belongs_to :customer, :foreign_key => "cust_key"
4 set_primary_key "order_key”
5 end
Consider the following piece of Ruby-on-Rails code.
1 <table>
2 <% Customers.all.each.do |c| %>
3 <tr>
4 <td><%= c.address %></td>
5 <td><%= c.orders.count() %></td>
6 </tr>
7 <% end %>
8 </table>
Questions:
Provide the SQL queries that will result from executing this piece of Ruby-on-Rails. How many SQL queries in total will be executed?
2 queries
SELECT address FROM customers
SELECT COUNT(*) FROM orders where orders.cust_key= customers.cust_key;
Write a jsp fragment that issues only one SQL query and creates identical html with the Ruby-on-Rails fragment above.

I know that this is an old question, and you've probably forgotten it but ...
If you change:
<% Customers.all.each.do |c| %>
<tr>
<td><%= c.address %></td>
<td><%= c.orders.count() %></td>
</tr>
<% end %>
to
<% Customers.includes(:orders).each.do |c| %>
<tr>
<td><%= c.address %></td>
<td><%= c.orders.length %></td>
</tr>
<% end %>
You'll display the customer information in one SQL call.
The includes method, changes the request so that it uses a single query with a join, to gather all customers with their corresponding order records
Note that I've used length rather than count, as count will call a SQL count for each customer (c) object, whereas length will look at the length of orders data already gathered in the first SQL call.

Related

Query model for all possible values of a column - Ruby Rails [duplicate]

How can I get unique values from column in the table?
For example, I have this Products table:
ID NAME CATEGORY
1 name1 1st_cat
2 name2 2nd_cat
3 name3 1st_cat
Here I want to get only 2 values - 1st_cat and 2nd_cat:
<%Products.each do |p|%>
<%=p.category%>
<%end%>
Two more ways:
Product.select(:category).map(&:category).uniq # Ruby does the work
Product.uniq.pluck(:category) # DB does the work (superior)
For Rails >= 5.1 use:
Product.distinct.pluck(:category) # DB does the work (superior)
...because Relation#uniq was deprecated.
I think you can do this:
<% Products.select("DISTINCT(CATEGORY)").each do |p| %>
<%= p.category %>
<% end %>
Source: http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields
This does all the work in the database server. The result is a simple array.
<% Product.distinct(:category).pluck(:category).each do |category|
<%= category %>
<% end %>
Rails will generate SQL that works on any database (Postgres, MySQL, etc).
SELECT DISTINCT "products"."category" FROM "products"
I suggest to use Products.all.distinct.pluck(:category) because uniq has been deprecated since rails 5 and it will be removed on rails 5.1
Try this (in the rails console)
Product.group(:category)
Product.group(:category).each { |p| p.name }
For postgres
<% Product.select("DISTINCT ON (category) *").each do |category|
<%= category %>
<%= name %>
<% end %>
Update
even better
<% Product.select(%(DISTINCT ON (category) "#{Product.table_name}".*)).each do |category|
<%= category %>
<%= name %>
<% end %>
because it can return wrong columns when you do joins (e.g. returns id column from joined table, but not products)
If you or anyone want to get two or more attributes from a table like products, based on a distinct feature of an attribute, only this solution will help you for Rails >= 5.1
distinct_products = Product.select("DISTINCT ON (category) *")
# it's an active record relation class.
> distinct_products.class
=> Product::ActiveRecord_Relation
N.B. Don't use .pluck() on the distinct_products. It will reselect from the products table and the distinct feature will not work anymore.
Needed to get unique output and was trying the 'uniq' method unsuccessfully. Tried several solutions posted here unsuccessfully. I'm using devise which gives me access to the current_user method and working with two tables, one being a join (an item has_many :things).
This solution ultimately worked for me :
#current_user.things.select(:item_fk).distinct.each do |thing|
<%= thing.item.attribute %>
<% end %>

Rails list created/updated records within last 24 hours

I'm trying to list records for a locations view of recently created at or updated records from the last 24 hours using activerecord but am a beginner developer needing some help.
Does anyone know a solution for implementing this in the controller/view? Thanks in advance for the help.
Since you're using Rails, I will assume that you have these files, corresponding to a Locations resource:
app/views/locations/index.html.erb
app/controllers/locations_controller.rb
app/models/location.rb
There are a few ActiveRecord alternatives for querying records in the past 24 hours:
This example demonstrates the concept that you can specify a range for querying the timestamp columns.
#locations = Location.where(updated_at: (Time.now - 24.hours)..Time.now)
As pointed out in the comments below, there may be a fraction of a second precision error with the above query. You can store a variable, now = Time.now, to ensure that your query spans exactly 24 hours.
now = Time.now
#locations = Location.where(updated_at: (now - 24.hours)..now)
You could eliminate the subtraction operation and let Rails handle it for you, which may also result in a slight offset from an exact window of 24 hours.
#locations = Location.where(updated_at: 24.hours.ago..Time.now)
You can also forego the hash syntax in the where parameters, passing a SQL string that filters with the > comparison operator.
#locations = Location.where('updated_at > ?', 24.hours.ago)
In your controller, add an index action, with your preferred query approach:
def index
#locations = Location.where(updated_at: 24.hours.ago..Time.now)
end
In your view, add these lines:
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Created_At</th>
<th>Updated_At</th>
</tr>
</thead>
<tbody>
<% #locations.each do |location| %>
<tr>
<td><%= location.id %></td>
<td><%= location.name %></td>
<td><%= location.created_at %></td>
<td><%= location.updated_at %></td>
</tr>
<% end %>
</tbody>
</table>

rails complex table

i'm having a huge problem with creating this table.
I have a model
Unit
id
floor
unitnumber
here is my current code for view
<% block.units.each do |unit| %>
....
<% end %>
I need to loop through the entire block, get all the unique unitnumber and floor. Create a table like this.
BLOCKNO Unitnumber1 Unitnumber2 Unitnumber3 Unitnumber4 Unitnumber5 Unitnumber6
Floor10 unit_id unit_id unit_id unit_id
Floor9
Floor8
<% block.each do |block| %>
<% block.units.each do |unit| %>
...
<% end %>
<% end %>

Rails 3 HABTM not changing created_at and updated_at fields

I have two models: Product and Categories. They have a HABTM relationship.
At products form i have:
<% Category.find(:all).each do |c| %>
<%= check_box_tag 'product[category_ids][]', c.id, #product.category_ids.include?(c.id) %> <%=c.name%>
<% end %>
It works perfectly but when a categories_products record is created, the created_at field is empty ( 0000-00-00 00:00:00 ).
How can i make Rails create/update those fields?
Thanks.

Defining the order that distinct items are listed in

I am trying to construct a simple site which compares the best time for a race for a number of individuals, however, I am having a lot of difficulty using distinct which seems to be causing me a number of unexpected problems...
I have two databases - Result and Athlete (athlete has many results)
I am attempting to identify the quickest time for each athlete for a specific event and then put them in order. In order to do this, I need to create a list of unique athlete names, BUT they also have to be in the sequence of increasing time (i.e. slower). I am currently using:
<% #filtered_names = Result.where(:event_name => params[:justevent]).joins(:athlete).order('performance_time_hours ASC').order('performance_time_mins ASC').order('performance_time_secs ASC').order('performance_time_msecs ASC').select('distinct athlete_id') %>
This appeared to be working, however, I have discovered that if the last entry in the results database is the slowest across all athletes, this athlete ends up at the end of my list of names, EVEN IF one of their previous results is the fastest of all times recorded!
Is someone able to tell me whether distinct works in some strange way and how I can get around this issue? If the bottom result is the quickest the script works perfectly as it is...
For the sake of completeness, I need this information in order to run the following code:
<% #filtered_names.each do |filtered_name| %>
<% #currentathleteperformance = Result.where(:event_name => params[:justevent]).where(:athlete_id => filtered_name.athlete_id).order('performance_time_hours ASC').order('performance_time_mins ASC').order('performance_time_secs ASC').order('performance_time_msecs ASC').first() %>
<% #currentathlete = Athlete.where(:id => filtered_name.athlete_id).first() %>
<td><%= #currentathleteperformance.performance_time_mins %>:<%= #currentathleteperformance.performance_time_secs %>:<%= #currentathleteperformance.performance_time_msecs %> </td>
<td><%= #currentathleteperformance.wind_speed %></td>
<td><%= #currentathleteperformance.athlete_name %></td>
<td><%= #currentathlete.gender %></td>
<td><%= #currentathlete.sec %></td>
<td><%= #currentathleteperformance.competition_name %></td>
<td><%= #currentathleteperformance.round %></td>
<td><%= #currentathleteperformance.position %></td>
<td><%= #currentathleteperformance.performance_date %></td>
<td><%= #currentathlete.coach_name %></td>
<% end %>
I would use 1 column performance_time of data type time to replace all of:
performance_time_hours
performance_time_mins
performance_time_secs
performance_time_msecs
Or interval if more than 24 hours for one performance are possible.
I am no good with Ruby syntax, but the query to get what you want could look like this - assuming that athletes can perform multiple times per event and event_name is unique:
SELECT athlete_id, min(performance_time) AS min_performance_time
FROM result
WHERE event_name = params[:justevent]
GROUP BY athlete_id
ORDER BY min(performance_time), athlete_id
I order by athlete_id in addition, but that's just an arbitrary measure to break ties in a stable manner.
DISTINCT just takes the first row according to the sort order for every set of duplicates. To achieve the same result with DISTINCT you'd need a subselect:
SELECT athlete_id, performance_time
FROM (
SELECT DISTINCT ON (athlete_id)
athlete_id, performance_time
FROM result
WHERE event_name = params[:justevent]
ORDER BY athlete_id, performance_time
) a
ORDER BY performance_time, athlete_id
You have to ORDER BY athlete_id to get distinct athletes and cannot order by minimum performance_time first on the same query level. Therefore, you'd have to put the result of the SELECT DISTINCT in a subselect and sort by time in additional step.