How to implement AND clause in Rails Active Record? - ruby-on-rails

I have the following query:
select source_names.id as source_id, source_names.name as source_name, source_types.id as source_type_id,source_types.name type_name,event_sources.id
from source_names
left join source_types
on source_type_id = source_types.id
left join event_sources
on source_names.id = event_sources.source_id and event_id = 1
result = SourceName.joins('
LEFT JOIN source_types ON source_type_id = source_types.id
LEFT JOIN event_sources ON source_names.id = event_sources.source_id
').where('event_id =?',event_id).select('source_names.id as source_id, source_names.name as source_name, source_types.id as source_type_id,source_types.name type_name,event_sources.id').all
yields:
select source_names.id as source_id, source_names.name as source_name, source_types.id as source_type_id,source_types.name type_name,event_sources.id
from source_names
left join source_types
on source_type_id = source_types.id
left join event_sources
on source_names.id = event_sources.source_id WHERE event_id = 1
But I want and event_id = 1
How'd I accomplish that?

If you don't want a WHERE, don't use .where
Just add it to your joins:
SourceName.joins('
LEFT JOIN source_types ON source_type_id = source_types.id
LEFT JOIN event_sources ON source_names.id = event_sources.source_id and event_sources.event_id = 1')

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")

Multi-dimension instance loop

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.

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