Rails impressionist gem - missing FROM-clause entry for table "impressions" - sql

I am using Rails 4.2 and have set up the impressionist gem which is working fine for logging page impressions.
I am trying to do exactly the same thing as in this Stackoverflow post but the answer isn't working. I tried:
start_time = 30.days.ago
#mostReadAlbums30Days = Album.joins(:impressions).where("impressions.created_at<='#{Time.now}' and impressions.created_at >= '#{start_time}'").group("impressions.impressionable_id").order("count(impression‌​s.id) DESC")
This produces the following SQL and error message
PG::UndefinedTable: ERROR: missing FROM-clause entry for table
"impression‌​s" LINE 1: ... BY impressions.impressionable_id ORDER BY
count(impression...
^ : SELECT "albums".* FROM "albums" INNER JOIN "impressions" ON
"impressions"."impressionable_id" = "albums"."id" AND
"impressions"."impressionable_type" = $1 WHERE
(impressions.created_at<='2015-01-02 00:50:18 -0200' and
impressions.created_at >= '2014-12-03 02:50:18 UTC') GROUP BY
impressions.impressionable_id ORDER BY count(impression‌​s.id) DESC
I'm using Postgresql v9.3.5.2. How can I get this query to work?

The main problem (per comment):
There's a subtle typo in your query. It contains a Unicode Character ZERO WIDTH SPACE (U+200B) between the n and s of ORDER BY count(impression‌s.id). Look at how impressions gets line-broken in the rendering of the error message, that wouldn't happen otherwise.
The GROUP BY problem:
since the query selects albums.*, it has to GROUP BY albums.id rather than GROUP BY impressions.impressionable_id (assuming that albums.id is a primary key). This is numerically equivalent since the tables are equi-joined through these two fields anyway, but as it seems, the SQL engine in this context can't figure out this equivalency by itself.

Related

Postgres missing FROM-clause entry for table error caused by WHERE clause

I have the following query:
SELECT books.id, author, title, price, books.created, movies.budget, movies.revenue
FROM books
INNER JOIN movies
ON books.movie_id=movies.id
WHERE price >= $1
AND (movies.budget = $2 OR movies.revenue = $2)
ORDER BY books.created ASC
LIMIT 5 OFFSET 0
This throws me a missing FROM-clause entry for table \"movies\" error. I debugged it and the problematic part is the AND (movies.budget = $2 OR movies.revenue = $2), without it the query runs fine .
There are a lot of questions about this error but I couldn't find one where the problem/solution applied to my case. Does anybody have a clue where the problem is here?

Postgres ORDER BY value inside json causes "column does not exist" error [duplicate]

As a newbie to Postgresql (I'm moving over because I'm moving my site to heroku who only support it, I'm having to refactor some of my queries and code. Here's a problem that I can't quite understand the problem with:
PGError: ERROR: column "l_user_id" does not exist
LINE 1: ...t_id where l.user_id = 8 order by l2.geopoint_id, l_user_id ...
^
...query:
select distinct
l2.*,
l.user_id as l_user_id,
l.geopoint_id as l_geopoint_id
from locations l
left join locations l2 on l.geopoint_id = l2.geopoint_id
where l.user_id = 8
order by l2.geopoint_id, l_user_id = l2.user_id desc
clause "l.user_id as l_user_id, l.geopoint_id as l_geopoint_id" was added because apparently postgres doesn't like order clauses with fields not selected. But the error I now get makes it look like I'm also not getting aliasing. Anybody with postgres experience see the problem?
I'm likely to have a bunch of these problems -- the queries worked fine in mySql...
In PostgreSQL you can not use expression with an alias in order by. Only plain aliases work there. Your query should look like this:
select distinct
l2.*,
l.user_id as l_user_id,
l.geopoint_id as l_geopoint_id
from locations l
left join locations l2 on l.geopoint_id = l2.geopoint_id
where l.user_id = 8
order by l2.geopoint_id, l.user_id = l2.user_id desc;
I assume you mean that l2.user_id=l.user_id ought to go first.
This is relevant message on PostgreSQL-general mailing list. The following is in the documentation of ORDER BY clause:
Each expression can be the name or
ordinal number of an output
column (SELECT list item), or it
can be an arbitrary expression formed
from input-column values.
So no aliases when expression used.
I ran into this same problem using functions from fuzzystrmatch - particularly the levenshtein function. I needed to both sort by the string distance, and filter results by the string distance. I was originally trying:
SELECT thing.*,
levenshtein(thing.name, '%s') AS dist
FROM thing
WHERE dist < character_length(thing.name)/2
ORDER BY dist
But, of course, I got the error "column"dist" does not exist" from the WHERE clause. I tried this and it worked:
SELECT thing.*,
(levenshtein(thing.name, '%s')) AS dist
FROM thing
ORDER BY dist
But I needed to have that qualification in the WHERE clause. Someone else in this question said that the WHERE clause is evaluated before ORDER BY, thus the column was non-existent when it evaluated the WHERE clause. Going by that advice, I figured out that a nested SELECT statement does the trick:
SELECT * FROM
(SELECT thing.*,
(levenshtein(thing.name, '%s')) AS dist
FROM thing
ORDER BY dist
) items
WHERE dist < (character_length(items.name)/2)
Note that the "items" table alias is required and the dist column alias is accessible in the outer SELECT because it's unique in the statement. It's a little bit funky and I'm surprised that it has to be this way in PG - but it doesn't seem to take a performance hit so I'm satisfied.
You have:
order by l2.geopoint_id, l_user_id = l2.user_id desc
in your query. That's illegal syntax. Remove the = l2.user_id part (move it to where if that's one of the join conditions) and it should work.
Update Below select (with = l2.user_id removed) should work just fine. I've tested it (with different table / column names, obviously) on Postgres 8.3
select distinct
l2.*,
l.user_id as l_user_id,
l.geopoint_id as l_geopoint_id
from locations l
left join locations l2 on l.geopoint_id = l2.geopoint_id
where l.user_id = 8
order by l2.geopoint_id, l_user_id desc
"was added because apparently postgres doesn't like order clauses with fields not selected"
"As far as order by goes - yes, PostgresQL (and many other databases) does not allow ordering by columns that are not listed in select clause."
Just plain untrue.
=> SELECT id FROM t1 ORDER BY owner LIMIT 5;
id
30
10
20
50
40
(5 rows)

Use includes() instead of joins() with Rails

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)

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.

ORDER BY issue in Postgres (Heroku)

The following code works for Postgres (Heroku):
#messages = Message.select("DISTINCT
ON (messages.conversation_id)
*").where("messages.sender_id = (?) OR messages.recipient_id = (?)",
current_user.id, current_user.id)
However, when attempting to order the results by appending .order("messages.read_at DESC") I receive the following error:
ActionView::Template::Error (PGError: ERROR: column id_list.alias_0 does not exist)
In looking at the generated SQL, I see that an alias is being created around the ORDER BY statement when not asked for:
messages.recipient_id = (32))) AS id_list ORDER BY id_list.alias_0 DESC)
I've not been able to figure out a workaround short of using "find_by_sql" for the entire statement - which takes a heavy toll on the app.
Don't vote this, I only post because posting many lines in comments does not show very well.
I would write a "query that returns messages grouped by their conversation_id, so that the last message in each conversation is shown" like this:
SELECT m.*
FROM messages m
JOIN
( SELECT conversation_id
, MAX(created_date) AS maxdate
FROM messages
WHERE ...
GROUP BY conversation_id
) AS grp
ON grp.conversation_id = m.conversation_id
AND grp.maxdate = m.created_date
ORDER BY m.read_at DESC
No idea how this can be done in Heroku or if it even possible, but it avoids the DISTINCT ON. If that's causing the error, it may be of help.