We have created a query on Rails with Postgres database, where we want courses to be in order by position as data available in an array, in our case it is course_ids.
A course_ids array contains courses' ids in squences.
Course.includes(:course_series).
where("course_id IN (?)", course_ids).
order("position(course_id::text in '?')", course_ids.join(',')).
order('course_name asc')
but it showing below error
ActiveRecord::StatementInvalid in FrontendController#get_courses
PG::InvalidColumnReference: ERROR: ORDER BY position 52 is not in select list
LINE 1: ...9)) ORDER BY position(course_id::text in '?'), 11,52, course...
^
: SELECT "at_courses".* FROM "at_courses" WHERE "at_courses"."deleted_at" IS NULL AND (course_id IN (52,11)) ORDER BY position(course_id::text in '?'), 52,11, course_name asc
Extracted source (around line #598):
Could you please share what went wrong here? Please go easy on me. I am not a technical guy.
Thanks!
Related
I have got difficulties group in PostGreSQL. My code below
Invoice.select("customer_id, due_date, sum(balance) AS total_balance, total_mount").group(:customer_id)
I have got the errors
Invoice Load (1.8ms) SELECT customer_id, due_date, sum(balance) AS total_balance, total_amount FROM "records" WHERE "records"."type" IN ('Invoice') GROUP BY "records"."customer_id"
ActiveRecord::StatementInvalid: PG::GroupingError: ERROR: column "records.due_date" must appear in the GROUP BY clause or be used in an aggregate function
enter code here
LINE 1: SELECT customer_id, due_date, sum(balance) AS total_balance,...
UPDATE
Thanks for #slicedpan for the solution. I have update like below code.
Invoice.select("customer_id, MAX(due_date), SUM(balance) AS total_balance").group(:customer_id)
I have read many of articles about that but It still show the error.
This error is due to the fact that Postgres doesn't know what to do with the due_date column. The query you have written is basically:
for each customer, show me the total sum of the balances for all their invoices, and the due date for one of their invoices.
The problem here is that in PostgreSQL you have to be explicit about which invoice you want to show the due_date of, whereas in MySQL or SQLite it will pick one (can't remember how off the top of my head). In this case I think it would make more sense to leave out the due_date from the select, otherwise use MAX(due_date) to get the most recent, or something like that.
You can get the same functionality as MySQL/SQLite if you do it like this:
Invoice.select("DISTINCT ON (customer_id) customer_id, due_date, sum(balance) over(partition by customer_id) AS total_balance, total_mount")
It will sum balance and select "random" due_date/total_mount for each customer_id. Just like non-standard GROUP BY possible in those 2 other RDBMS.
I have a query like the following:
Author.select('authors.*, max(books.published_at) as last_publishing')
.joins(:books)
.group('authors.id')
This does what I want (returns a list of authors annotated with their most recent publishing date), but if I try to call count on this query, there is an issue.
SELECT COUNT(authors.*, max(books.published_at) as last_publishing)
AS count_authors_all_max_books_published_at_as_last_publishing, authors.id
AS authors_id FROM "authors"
INNER JOIN "books"
ON "books"."author_id" = "authors"."id"
GROUP BY authors.id
*** ActiveRecord::StatementInvalid Exception: PG::SyntaxError: ERROR: syntax error at or near "as"
LINE 1: ...COUNT(authors.*, max(books.published_at) as last_pu...
Obviously this is not the SQL I want to generate - I just want a SELECT COUNT(*) FROM ( ) myQuery.
I saw there was a similar issue with Rails 4 - has anyone else come up against this/is there a workaround? I can do query.to_a.size, but I would prefer to just be able to use the count method for my, and my coworkers, future sanity.
You should remove select temporary before call count
authors = Author.select('authors.*, max(books.published_at) as last_publishing')
.joins(:books)
.group('authors.id')
total_authors = authors.except([:includes]).count(:all)
I'm trying to combine a uniq statement with a select("distinct") statement in Active Record, and it results in two DISTINCT keywords, which of course leads to an invalid query. This is the simplest example I have come up with. (Mark that is is simplified in order to help you understand the problem - I'm not simply asking for how I get out distinct ids from a database.)
Product.all.uniq.select("distinct id").map(&:id)
This gives me this error message:
Product Load (0.7ms) SELECT DISTINCT distinct id FROM "products"
ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: syntax error at or near "distinct"
LINE 1: SELECT DISTINCT distinct id FROM "products"
^
: SELECT DISTINCT distinct id FROM "products"
Why do I get two DISTRINCT keywords here? Is there any way to avoid it? Using uniq twice works, but I need to do a select for one of the filters I'm implementing.
Edit: The select("distinct..") has to go before the uniq statement.
uniq already uses DISTINCT. Either use uniq or select("DISTINCT"). Moreover, you should use pluck, and not map over the records and select the id.
What you really want to use is
Product.pluck(:id)
or
Product.all.ids
What's not clear to me, is why you want to use distinct. How comes an ID has duplicate values?
If the field is different than an id, simply use
Product.select("DISTINCT(field)").map(&:field)
or even better
Product.uniq.pluck(:field)
Hence in your case
Product.uniq.pluck(:id)
# => SELECT DISTINCT "products"."id" FROM "products"
You can use uniq(false) to disable a previously used uniq scope. So your example would go like this:
scope = Product.all.uniq
scope.uniq(false).select("distinct id").map(&:id)
Source code documentation can be found here.
I'm trying to sort a list of items based on the value of field on a joined table. Here's what I've got so far:
FeaturedEvent.joins(:event).order('event.start_datetime').limit(5)
This looks right to me but when it's run it returns a Postgres error about there being a missing FROM statement:
PG::UndefinedTable: ERROR: missing FROM-clause entry for table "event" LINE 1: ...ts"."id" = "featured_events"."event_id" ORDER BY event.star... ^ : SELECT "featured_events".* FROM "featured_events" INNER JOIN "events" ON "events"."id" = "featured_events"."event_id" ORDER BY event.start_datetime LIMIT 5
I tried the suggestions in this post about putting the ordering in default scope but it came out with the same error – I'm guessing it's a Postgres thing.
How can I fix this?
Thanks!
Try
FeaturedEvent.includes(:event).order('events.start_datetime').limit(5)
In your order the table name should be the real database table name.
As I guess, the table name must be events
Your table name is events so you just have to add s in event
FeaturedEvent.joins(:event).order('events.start_datetime').limit(5)
I have this statement to choose a given number of random records from the database that match certain set of tags. I am using act-as-taggable-on gem for tagging.
questions=Question.select('questions.*,RANDOM()').tagged_with(tags,:any=>true).order("RANDOM()").limit(test.no_of_questions)
I am using postgresql and I get the following error.
PG::Error: ERROR: syntax error at or near "DISTINCT"
LINE 1: SELECT questions.*,RANDOM(), DISTINCT questions.* FROM "que...
^
: SELECT questions.*,RANDOM(), DISTINCT questions.* FROM "questions" JOIN taggings quest_taggings_14e6dd0 ON quest_taggings_14e6dd0.taggable_id = "questions".id AND quest_taggings_14e6dd0.taggable_type = 'Question' WHERE (quest_taggings_14e6dd0.tag_id = 1) ORDER BY RANDOM() LIMIT 3
I am not sure what to do because I think the Distinct part is inserted by the tagging gem.
Thanks in advance!
You can do it along these lines
Question.tagged_with(tags,:any=>"true").order("RANDOM()").limit(limit_number)
update
As shown here http://archives.postgresql.org/pgsql-sql/2010-10/msg00004.php
You need to put the DISTINCT and the ORDER BY in separate query levels.
Apparently, the above Query would work with other DB but not Postgresql
Nevermind Ive found the solution.
I did this:
questions=Question.tagged_with(tags,:any=>true)
questions=questions.select('questions.*,RANDOM()').order("RANDOM()").limit(test.no_of_questions)
This way the questions.* wasnt included twice in the select statement.