Multi-dimension instance loop - ruby-on-rails

I am trying to use a custom sql query to display different attributes for a product i.e. Size and Price. The query I have when running in console displays as it should
SELECT products.id, products.name, variant_properties.description, LEFT(variant_properties.description,1) as short_desc, variants.price FROM products
INNER JOIN product_properties ON product_properties.product_id = products.id
INNER JOIN variant_properties on product_properties.property_id = variant_properties.property_id AND variant_properties."primary" = true
INNER JOIN properties ON properties.id = product_properties.property_id AND properties.id = variant_properties.property_id AND properties.display_name = 'Size'
INNER JOIN variants on variants.product_id = products.id AND variants.id = variant_properties.variant_id
In my HAML template I have done the following
- #products.each_with_index do |product, i|
.product-list.grid-block
.small-8.grid-content.text-center
%h4= product.name.titlecase
- #sizes.each do |size|
= link_to size.short_desc, product, class: 'hollow button tiny'
%small= size.price
and in the controller
products = Product.active
# products = Product.active.includes(:variants)
product_types = nil
if params[:product_type_id].present? && product_type = ProductType.find_by_id(params[:product_type_id])
product_types = product_type.self_and_descendants.map(&:id)
end
if product_types
#products = products.where(product_type_id: product_types)
else
#products = products
end
#sizes = Product.find_by_sql("SELECT products.id, LEFT(variant_properties.description,1) as short_desc, variants.price FROM products
INNER JOIN product_properties ON product_properties.product_id = products.id
INNER JOIN variant_properties on product_properties.property_id = variant_properties.property_id
INNER JOIN properties ON properties.id = product_properties.property_id AND properties.id = variant_properties.property_id AND properties.display_name = 'Size'
INNER JOIN variants on variants.product_id = products.id AND variants.id = variant_properties.variant_id")
Ideally I am trying to get it to look something like below, though I am having issues achieving this

The first thing is notice is that Model.find_by_sql will return a list of models and nothing more no matter what you select in your sql query.
So the solution I suggest is trying to convert to ActiveRecord::Relation like this:
Product.joins(:product_properties)
.joins('INNER JOIN variant_properties on product_properties.property_id = variant_properties.property_id')
.joins('INNER JOIN properties ON properties.id = product_properties.property_id AND properties.id = variant_properties.property_id AND properties.display_name = \'Size\'')
.joins('INNER JOIN variants on variants.product_id = products.id AND variants.id = variant_properties.variant_id')
.pluck('products.id', 'LEFT(variant_properties.description,1)', 'variants.price')
I haven't tried yet but I think it could produce an array of arrays contains the value you need.

Related

how to make one from the the following two queries

i have two queries:
the first one query is:
SELECT sale.saleid,
sale.totalpaid,
item.itemname AS item,
stock.saleprice AS Price,
invoice.qty,
sale.discount,
invoice.saleprice AS [invoice saleprice],
cetegory.catname AS [Cateogory],
cetegory.subcat AS [Sub Catgry],
vehicle.vehicle_name AS [Vehicle],
vehicle.vehicle_model AS [Model],
item.model_number AS [Part No.],
sale.date,
stock.size,
sale.customerid
FROM invoice
JOIN item
ON invoice.itemid = item.itemid
JOIN sale
ON invoice.saleid = sale.saleid
JOIN stock
ON item.itemid = stock.itemid
JOIN cetegory
ON item.catid = cetegory.catid
JOIN vehicle
ON item.vehicleid = vehicle.vehicleid
WHERE sale.saleid = 5
and the second query is:
SELECT customer.customername,
customer.customercontact,
customer.customeraddress,
account.account_type
FROM account
JOIN customer
ON customer.customerid = account.customerid
Now i want to combine these two queries by customer id because i have "custome id" in sale table
You could use a CTE and then join both:
WITH CUST
AS
(SELECT customer.customername,
customer.customercontact,
customer.customeraddress,
account.account_type ,
customer.customerid
FROM account
JOIN customer
ON customer.customerid = account.customerid
),
SALES
AS
(
SELECT sale.saleid,
sale.totalpaid,
item.itemname AS item,
stock.saleprice AS Price,
invoice.qty,
sale.discount,
invoice.saleprice AS [invoice saleprice],
cetegory.catname AS [Cateogory],
cetegory.subcat AS [Sub Catgry],
vehicle.vehicle_name AS [Vehicle],
vehicle.vehicle_model AS [Model],
item.model_number AS [Part No.],
sale.date,
stock.size,
sale.customerid
FROM invoice
JOIN item
ON invoice.itemid = item.itemid
JOIN sale
ON invoice.saleid = sale.saleid
JOIN stock
ON item.itemid = stock.itemid
JOIN cetegory
ON item.catid = cetegory.catid
JOIN vehicle
ON item.vehicleid = vehicle.vehicleid
WHERE sale.saleid = 5
)
SELECT * FROM CUST
LEFT JOIN SALES
ON CUST.customerid = SALES.customerid

Delete multiple tables in a single query with join in rails 5

This is my query in rails, I want to delete entries from feed and feed mappings table which match certain conditions in a single query, If I use destroy_all it deletes items one by one, first it will delete feed and then feed_mappings for each entry, whereas If I can just change the Select statement on the resulting query into Delete feed, feed_mappings I can delete everything in one query. Help me solve this problem in a single query.
Feed.joins(:feed_mappings)
.joins('inner join notifications on notifications.id = feed_mappings.source_id')
.joins('inner join user_feedbacks on user_feedbacks.source_id = notifications.picked_for_company')
.joins('inner join user_feedback_contexts on user_feedback_contexts.user_feedback_id = user_feedbacks.id')
.where(user_feedbacks: {source_type: 'Company', user_id: user.id},
user_feedback_contexts: {context: 'block'},
notifications: {user_id: user.id},
feed_mappings: {source_type: 'Notifications::Notification'})
This generates
SELECT `feeds`.* FROM `feeds`
INNER JOIN `feed_mappings`
ON `feed_mappings`.`feed_id` = `feeds`.`id`
INNER JOIN notifications
ON notifications.id = feed_mappings.source_id
INNER JOIN user_feedbacks
ON user_feedbacks.source_id = notifications.picked_for_company
INNER JOIN user_feedback_contexts
ON user_feedback_contexts.user_feedback_id = user_feedbacks.id
WHERE `user_feedbacks`.`source_type` = 'Company'
AND `user_feedbacks`.`user_id` = 6
AND `user_feedback_contexts`.`context` = 'block'
AND `notifications`.`user_id` = 6
AND `feed_mappings`.`source_type` = 'Notifications::Notification'
What I want instead
DELETE `feeds`, `feed_mappings` FROM `feeds`
INNER JOIN `feed_mappings`
ON `feed_mappings`.`feed_id` = `feeds`.`id`
INNER JOIN notifications
ON notifications.id = feed_mappings.source_id
INNER JOIN user_feedbacks
ON user_feedbacks.source_id = notifications.picked_for_company
INNER JOIN user_feedback_contexts
ON user_feedback_contexts.user_feedback_id = user_feedbacks.id
WHERE `user_feedbacks`.`source_type` = 'Company'
AND `user_feedbacks`.`user_id` = 6
AND `user_feedback_contexts`.`context` = 'block'
AND `notifications`.`user_id` = 6
AND `feed_mappings`.`source_type` = 'Notifications::Notification'
All the joins complicates things, but does the following work?
Feed.joins(:feed_mappings)
.joins('inner join notifications on notifications.id = feed_mappings.source_id')
.joins('inner join user_feedbacks on user_feedbacks.source_id = notifications.picked_for_company')
.joins('inner join user_feedback_contexts on user_feedback_contexts.user_feedback_id = user_feedbacks.id')
.where(user_feedbacks: {source_type: 'Company', user_id: user.id},
user_feedback_contexts: {context: 'block'},
notifications: {user_id: user.id},
feed_mappings: {source_type: 'Notifications::Notification'}).delete_all
FeedMappings.joins('inner join notifications on notifications.id = feed_mappings.source_id')
.joins('inner join user_feedbacks on user_feedbacks.source_id = notifications.picked_for_company')
.joins('inner join user_feedback_contexts on user_feedback_contexts.user_feedback_id = user_feedbacks.id')
.where(user_feedbacks: {source_type: 'Company', user_id: user.id},
user_feedback_contexts: {context: 'block'},
notifications: {user_id: user.id},
feed_mappings: {source_type: 'Notifications::Notification'}).delete_all

How do I change this query to return an association instead of an array in Rails and Postgres?

Suppose I have this query:
t.pool_tournament_matches
.where(status: "unstarted")
.joins("INNER JOIN pool_tournament_match_users ON pool_tournament_match_users.pool_tournament_match_id = pool_tournament_matches.id")
.joins("INNER JOIN users ON users.id = pool_tournament_match_users.user_id")
.group("pool_tournament_matches.id")
.select("pool_tournament_matches.*, COUNT(users.id) AS user_count")
.select {|m| m.user_count == 2}
The result does return the right matches but it's an array which does not work well with RABL template engine. What converts the query to an array is
.select {|m| m.user_count == 2}` I think.
How would I do this using SQL so that it will return an association and I can chain it further if needed.
I've tried:
t.pool_tournament_matches
.where(status: "unstarted")
.joins("INNER JOIN pool_tournament_match_users ON pool_tournament_match_users.pool_tournament_match_id = pool_tournament_matches.id")
.joins("INNER JOIN users ON users.id = pool_tournament_match_users.user_id")
.group("pool_tournament_matches.id")
.select("pool_tournament_matches.*, COUNT(users.id) = 2)
but it does not work.
t.pool_tournament_matches
.where(status: "unstarted")
.joins("INNER JOIN pool_tournament_match_users ON pool_tournament_match_users.pool_tournament_match_id = pool_tournament_matches.id")
.joins("INNER JOIN users ON users.id = pool_tournament_match_users.user_id")
.group("pool_tournament_matches.id")
.having("COUNT(users.id) = 2")
.select("pool_tournament_matches.*, COUNT(users.id) AS user_count")

How to extract values from a custom SQL query

I have the following custom query whereby I am trying to extract the values so they are meaningful for my app
#sizes = Product
.joins(:product_properties)
.joins('INNER JOIN variant_properties on product_properties.property_id = variant_properties.property_id')
.joins('INNER JOIN properties ON properties.id = product_properties.property_id AND properties.id = variant_properties.property_id AND properties.display_name = \'Size\'')
.joins('INNER JOIN variants on variants.product_id = products.id AND variants.id = variant_properties.variant_id')
.pluck('products.id as prod_id', 'LEFT(variant_properties.description,1) as short_desc', 'variants.price as price')
below is the code within my view
- #sizes.each do |size|
- size.each do |var|
= var.price
= link_to var.short_desc, product, class: 'hollow button tiny'
%small= number_to_currency(var.price)
Problem is I am getting an error either stating no fixed num or no defined methods
Got it, pluck will return an array of arrays so you cannot call its elements like calling methods. It should be size[0], size[1]... instead.
For the ease of use I suggest you build a hash for this:
#product_sizes = #sizes.each_with_object({}) do |size, result|
result[size[0]] = {
'short_desc' => size[1],
'price' => size[2]
}
end
Then use it in your view:
- #products.each_with_index do |product, i|
.product-list.grid-block
.small-8.grid-content.text-center
%h4= product.name.titlecase
- if size = #product_sizes[product.id]
= link_to size['short_desc'], product, class: 'hollow button tiny'
%small= size['price']
Good luck!

Why I cannot use both ORDER BY and DISTINCT * in SQL?

I'm trying to do the following, and if I were to uncomment the distinct it will break. Also if I comment out the order and leave the distinct in, it will work.
Contestant.joins('INNER JOIN votes AS V ON V.contestant_id = contestants.id AND V.season_id = '+ season_number.to_s)
.joins('LEFT OUTER JOIN votes AS XV ON (XV.contestant_id = '+self.id.to_s+') AND (XV.tribal_council_key = V.tribal_council_key) AND XV.contestant_voted_for_id = V.contestant_voted_for_id')
.joins('INNER JOIN season_rosters ON season_rosters.season_id = V.season_id')
.where('V.is_jury_vote = (?) AND V.contestant_id <> (?) AND XV.tribal_council_key IS NOT NULL', :false, self.id)
.order('season_rosters.finished')
#.distinct
The error I get is below...
TinyTds::Error: Incorrect syntax near '*'.: EXEC sp_executesql N'SELECT DISTINCT *, __order FROM ( SELECT [contestants].*, DENSE_RANK() OVER (ORDER BY season_rosters.finished ASC) AS __order, ROW_NUMBER() OVER (PARTITION BY [contestants].* ORDER BY season_rosters.finished ASC) AS __joined_row_num FROM [contestants] INNER JOIN votes AS V ON V.contestant_id = contestants.id AND V.season_id = 6 LEFT OUTER JOIN votes AS XV ON (XV.contestant_id = 112) AND (XV.tribal_council_key = V.tribal_council_key) AND XV.contestant_voted_for_id = V.contestant_voted_for_id INNER JOIN season_rosters ON season_rosters.season_id = V.season_id WHERE (V.is_jury_vote = (''false'') AND V.contestant_id <> (112) AND XV.tribal_council_key IS NOT NULL) ) AS __sq WHERE __joined_row_num = 1 ORDER BY __order'
The issue is with this part:
SELECT DISTINCT *, __order
Try adding the required columns to your GROUP BY.
Contestant.joins('INNER JOIN votes AS V ON V.contestant_id = contestants.id AND V.season_id = '+ season_number.to_s)
.joins('LEFT OUTER JOIN votes AS XV ON (XV.contestant_id = '+self.id.to_s+') AND (XV.tribal_council_key = V.tribal_council_key) AND XV.contestant_voted_for_id = V.contestant_voted_for_id')
.joins('INNER JOIN season_rosters ON season_rosters.season_id = V.season_id')
.where('V.is_jury_vote = (?) AND V.contestant_id <> (?) AND XV.tribal_council_key IS NOT NULL', :false, self.id)
.order('season_rosters.finished')
.group('col1,col2,__order')
Also in your SQL error, order by is on a different column while in your code, it is on season_rosters.finished.

Resources