Use includes() instead of joins() with Rails - sql

I have two Models invoice and payevents. The relationship between them is invoice has_many payevents.
I'm using the following query to get all bills that have been fully paid.:
Invoice.joins(:payevents).group("invoice.id").having("sum(payevents.amount) >= invoice.amount")
This query works fine. However, it is not optimal since the result doesn't include the payevents. I tried to use includes instead of joins but it doesn't work.
Invoice.includes(:payevents).group("invoice.id").having("sum(payevents.amount) >= invoice.amount")
The error is
ActiveRecord::StatementInvalid: PG::GroupingError: ERROR: column "payevents.id" must appear in the GROUP BY clause or be used in an aggregate function
Any ideas what is wrong here?
I use PostgreSQL and Rails 4.1

If I correctly understand you - you should use subquery. Like this:
subquery = Invoice.joins(:payevents)
.group("invoice.id")
.having("sum(payevents.amount) >= invoice.amount")
.select("invoice.id id, sum(payevents.amount) amount").to_sql
query = Invoice.includes(:payevents).joins("JOIN (#{subquery}) subquery ON invoice.id = subquery.id")
So, you'll have Invoice, aggregated amount, filtered result by inner join of subquery and all payevents fields.

The much simpler solution is to explicitly use preload
Invoice.joins(:payevents).group("invoice.id").having("sum(payevents.amount) >= invoice.amount").preload(:payevents)

Related

"Your query does not include the specified expression..."

I have tried endless things to get this to work and it seems to break over and over again and not work. I'm trying to GROUP BY product after I have calculated the field quantity returned/quantity ordered, but I get the error
your query does not include the specified expression 'quantity_returned/quantity_ordered' as part of an aggregate function.
I do not want to GROUP BY quantity_returned, quantity_ordered, and product, I only want to GROUP BY product.
Here's what my SQL looks like currently...
SELECT
quantity_returned/quantity_ordered AS percentage_returned,
quantity_returned,
quantity_ordered,
returns_fact.product
FROM
Customer_dimension
INNER JOIN
(
Product_dimension
INNER JOIN
(
Day_dimension
INNER JOIN
returns_fact
ON Day_dimension.day_key = returns_fact.day_key
)
ON Product_dimension.product_key = returns_fact.product_key
)
ON Customer_dimension.customer_key = returns_fact.customer_key
GROUP BY returns_fact.product;
When you use a group by you need to actually include everything in your select that isn't a aggregate function.
I have no idea how your tables are set up, but I am throwing a blind dart. If you provide fields in each of the 4 tables someone will be better able to help.
SELECT returns_fact.product, count(quantity_returned), count(quantity_ordered), count(quantity_returned)/count(quantity_ordered) as percentage returned

SQL COUNT FORM JOIN TABLES

I have the following sql command:
SELECT "USERNAME"."TOPICS".VALUE,
"USERNAME"."TOPICS".QID,
"USERNAME"."QUESTION".QRATING
FROM "USERNAME"."TOPICS" JOIN "USERNAME"."QUESTION"
ON "USERNAME"."TOPICS".QID = "USERNAME"."QUESTION".QID
AND "USERNAME"."TOPICS".VALUE = 'kia'
ORDER BY QRATING DESC
It works really well, but I want to count how many element returns. So I tried to use:
SELECT COUNT("USERNAME"."TOPICS".QID)
FROM "USERNAME"."TOPICS" JOIN "USERNAME"."QUESTION"
ON "USERNAME"."TOPICS".QID = "USERNAME"."QUESTION".QID
AND "USERNAME"."TOPICS".VALUE = 'kia'
ORDER BY QRATING DESC
But I get the error :
Column reference 'USERNAME.TOPICS.VALUE' is invalid. When the SELECT
list contains at least one aggregate then all entries must be valid
aggregate expressions.
What is the problem?
Hmmm. The ORDER BY should be getting the error, not the SELECT. However, your query would be much easier to understand using table aliases:
SELECT COUNT(t.QID)
FROM "USERNAME"."TOPICS" t JOIN
"USERNAME"."QUESTION" q
ON t.QID = q.QID AND t.VALUE = 'kia';
If the first query works, I see no reason why this would not (and your original without the ORDER BY should also work).

PGError: ERROR: column “recipes.id” must appear in the GROUP BY clause or be used in an aggregate function

I have this SQL query in my DB which is causing a problem with PostgreSQL on heroku, Causing the page not to load with the above error in the heroku logs. I am using postgreSQL 9.1.6 so previous bugs have apparently been fixed
def self.top_countries
joins(:recipes).
select('countries.*, count(*) AS recipes_count').
group('countries.id').
order('recipes_count DESC')
end
I am unsure on how to refactor this so that it will work.Could anyone advise please?
Thank You
def self.top_countries
joins(:recipes).
select('countries.id, count(*) AS recipes_count').
group('countries.id').
order('recipes_count DESC')
This generates the SQL
select countries.id, count(*) AS recipes_count
from countries
join recipes on countries.id = recipes.country_id
group by countries.id
order by recipes_count
You'll notice that you only have 2 columns in the SELECT.
Not being a Heroku expert, I suspect you can get it to work by explicitly listing all column that you need from countries, and grouping by the full column list i.e.
def self.top_countries
joins(:recipes).
select('countries.id, countries.name, countries.other, count(*) AS recipes_count').
group('countries.id, countries.name, countries.other').
order('recipes_count DESC')
There might be a more concise way to join the original answer (top part) with another join to top_countries on countries.id to get the rest of the columns after the group by.

Group by query in Rails 3

I have the (working) code
counts = Registration.select('regulator_id').group('regulator_id').count
#regulators.each {|r| r.registration_count=counts[r.id]}
which allows me to show how many Registrations there are per Regulator. The query it generates is:
SELECT COUNT("registrations"."regulator_id") AS count_regulator_id, regulator_id AS regulator_id FROM "registrations" GROUP BY regulator_id
I would like to restrict my count to those registrations from the last scrape only, with a query like:
select
regulator_id, count(*)
from
registrations inner join
regulators on regulators.id = registrations.regulator_id
where
registrations.updated_at > regulators.last_scrape_start
group by
regulator_id
but I cannot get the syntax to work either using arel or find_by_sql. I am sure this is simple when you know the answer but it has cost me ages so far.
Thanks in advance.
Just add 'joins' and 'where'
Registration.joins(:regulator).where('registrations.updated_at > regulators.last_scrape_start').select('regulators.id').group('regulators.id').count

sql query question inner join

LEFT JOIN PatientClinics AB ON PPhy.PatientID = AB.PatientID
JOIN Clinics CL ON CL.ID = AB.ClinicID
AND COUNT(AB.ClinicID) = 1
I get error using Count(AB.ClinicID) = 1 (ClinicID has duplicate values in the table and
I want to use only 1 value of each duplicate value of ClinicId to produce result)
What mistake am I making?
I've never seen a COUNT() being used in a JOIN before. Maybe you should use:
HAVING COUNT(AB.ClinicID) = 1
instead.
Count() can't be used as a join/filter predicate. It can be used in the HAVING clause however. You should include the entire query in order to get a better example of how to rewrite it.
maybe investigate the HAVING clause instead of using COUNT where you put it.
hard to help without the full query.