I am not sure why I am getting the syntax error, according to this question everything should be okay. I could not find a way to execute a window function (postgres query which returns multiple columns GROUPED BY an individual column) that is the reason why I used raw SQL.
I am still new to Postgres, but I gathered that it may have to do with sanitization, but I do not know how to go about that either. Any help will be greatly appreciated, here is my code:
module TasksTestQuery
def self.call
query = "SELECT user_id, username, date, SUM(user_id) AS total_work, SUM(duration) AS total_duration OVER (PARTITION BY user_id) FROM tasks"
ActiveRecord::Base.connection.find_by_sql(query)
end
end
The exact error I'm getting is:
ActiveRecord::StatementInvalid
PG::SyntaxError: ERROR: syntax error at or near "(" LINE 1: SELECT user_id, username, date, SUM(user_id) AS total_work, SUM(duration) AS total_duration OVER (PARTITION BY user_id) FROM tasks
It should be
SUM(duration) OVER (PARTITION BY user_id) AS total_duration
Related
I have a jsonb column in my postgres performances table called authorization where I store the uuid of a user as a key and their authorization level as the value e.g.
{ 'sf4wfw4fw4fwf4f': 'owner', 'ujdtud5vd9': 'editor' }
I use the below Rails query in my Performance model to search for all records where the user is an owner:
class Performance < ApplicationRecord
def self.performing_or_owned_by(account)
left_outer_joins(:artists)
.where(artists: { id: account } )
.or(Performance.left_outer_joins(:artists)
# this is where the error happens
.where("authorization #> ?", { account => "owner" }.to_json)
).order('lower(duration) DESC')
.uniq
end
end
Where account is the account uuid of the user. However, when I run the query I get the following error:
ActiveRecord::StatementInvalid (PG::SyntaxError: ERROR: syntax error at or near "#>")
LINE 1: ..._id" WHERE ("artists"."id" = $1 OR (authorization #> '{"28b5...
The generated SQL is:
SELECT "performances".* FROM "performances"
LEFT OUTER JOIN "artist_performances" ON "artist_performances"."performance_id" = "performances"."id"
LEFT OUTER JOIN "artists" ON "artists"."id" = "artist_performances"."artist_id" WHERE ("artists"."id" = $1 OR (authorization #> '{"28b5fc7f-3a31-473e-93d4-b36f3b913269":"owner"}'))
ORDER BY lower(duration) DESC
I tried several things but keep getting the same error. Where am I going wrong?
The solution as per comment in the original question is to wrap the authorization in double-quotes. Eg:
.where('"authorization" #> ?', { account => "owner" }.to_json)
The ->> operator gets a JSON object field as text.
So it looks you need this query:
left_outer_joins(:artists).
where("artists.id = ? OR authorization ->> ? = 'owner'", account, account).
order('lower(duration) DESC').
uniq
I have a table named property_audit_version_histories.
i am fetching the records using the following code
#version_logs = PropertyAuditVersionHistory
.includes(:property_audit_version, :user)
.where(property_audit_version_id: params[:id])
The result contain 3 records, 2 of which have the same action and user_id
Now i need to group the records using the columns action, user_id
I am getting the following error when i try to group the records
#version_logs = PropertyAuditVersionHistory
.includes(:property_audit_version, :user)
.where(property_audit_version_id: params[:id])
.group("action, user_id")
PG::GroupingError: ERROR: column "property_audit_version_histories.id" must appear in the GROUP BY clause or be used in an aggregate function
Based on the thread PG::GroupingError: ERROR: column "events.id" must appear in the GROUP BY clause or be used in an aggregate function i have modified the code as follows
#version_logs = PropertyAuditVersionHistory
.includes(:property_audit_version, :user)
.group("property_audit_version_histories.id")
.where(property_audit_version_id: params[:id])
.group("action, user_id")
Now the error is gone but still the result is having 3 records. After grouping i expect only 2 records.
Any idea on how to fix this?
You cant select all columns like mysql in postgresql when doing aggregrates.
So I guess this should work.
#version_logs = PropertyAuditVersionHistory
.where(property_audit_version_id: params[:id])
.group("action", "user_id", "property_audit_version_id")
.select("user_id", "action", "property_audit_version_id")
I dont know how is your model but this should work. If you need more fields let me know
What you need to do is specify which columns you want with
.select("user_id")
But for the columns you know will be the same use max(columnName) as columnName
for example:
.select("MAX(user_id) as user_id, action")
Make sure you are 100% sure that those columns will be the same value after grouping.
I would like to write an ActiveRecord query to fetch all records which include specific foreign language words (case insensitive) in the description column of records table.
I think I can use mb_chars.downcase which converts international chars to lower case successfully.
> "ÖİÜŞĞ".mb_chars.downcase
=> "öiüşğ"
However, when I try to use mb_chars.downcase in ActiveRecord query I receive the following error:
def self.targetwords
target_keywords_array = ['%ağaç%','%üzüm%','%çocuk%']
Record.where('description.mb_chars.downcase ILIKE ANY ( array[?] )', target_keywords_array)
end
ActiveRecord::StatementInvalid (PG::UndefinedTable: ERROR: missing FROM-clause entry for table "mb_chars"
I will appreciate if you can guide me how to solve this problem.
You're trying too hard, you should let the database do the work. PostgreSQL knows how to work with those characters in a case-insensitive fashion so you should just let ilike deal with it inside the database. For example:
psql> select 'ÖİÜŞĞ' ilike '%öiüşğ%';
?column?
----------
t
(1 row)
You could say simply this:
def self.targetwords
target_keywords_array = ['%ağaç%','%üzüm%','%çocuk%']
Record.where('description ILIKE ANY ( array[?] )', target_keywords_array)
end
or even:
def self.targetwords
Record.where('description ilike any(array[?])', %w[ağaç üzüm çocuk].map { |w| "%#{w}%" })
end
or:
def self.targetwords
words = %w[ağaç üzüm çocuk]
likeify = ->(w) { "%#{w}%" }
Record.where('description ilike any(array[?])', words.map(&likeify))
end
As far as why
Record.where('description.mb_chars.downcase ILIKE ANY ( array[?] )', ...)
doesn't work, the problem is that description.mb_chars.downcase is a bit of Ruby code but the string you pass to where is a piece of SQL. SQL doesn't know anything about Ruby methods or using . to call methods.
I made a Select using Active Record with a lot of Joins. This resulted in duplicate values. After the select function there's the distinct function with value :id. But that didn't work!
Here's the code:
def join_query
<<-SQL
LEFT JOIN orders on orders.purchase_id = purchases.id
LEFT JOIN products on products.id = orders.complete_product_id
SQL
end
def select_query
<<-SQL
purchases.*,
products.reference_code as products_reference_code
SQL
end
result = Purchase.joins(join_query)
.select(select_query)
.distinct(:id)
Of course, neither distinct! or uniq functions worked. The distinct! returned a error from "ActiveRecord::ImmutableRelation" that I don't know what means.
To fix this I did a hack, converting the ActiveRecord_Relation object to an Array and I used the uniq function of Ruby.
What's going on here?
try this out:
def select_query
<<-SQL
DISTINCT ON (purchases.id) purchases.id,
products.reference_code as products_reference_code
SQL
end
add more comma separated column names in select clause
Purchase.select(select_query).joins(join_query)
I'm in Section 11.3.1 of the Rails Tutorial, and all tests were passing prior to this. Afterward, the home page (which has the micropost feed) breaks with this error:
PG::Error: ERROR: invalid input syntax for integer: "98, 1"
LINE 1: ...CT COUNT(*) FROM "microposts" WHERE (user_id IN ('98, 1') O...
^
: SELECT COUNT(*) FROM "microposts" WHERE (user_id IN ('98, 1') OR user_id = 101)
And several of the tests fail with a similar issue. Here's the first one:
1) Authentication authorization as wrong user visiting Users#edit page
Failure/Error: before { visit edit_user_path(wrong_user) }
ActionView::Template::Error:
PG::Error: ERROR: invalid input syntax for integer: ""
LINE 1: ...CT COUNT(*) FROM "microposts" WHERE (user_id IN ('') OR use...
^
Now, I am using PostgreSQL instead of the default SQLite3, so it may be that there is a syntax conflict, but I'm not positive. I'm not super familiar with Postgres (just using it to make the Heroku deploy cleaner).
It looks like the home page error is coming from the ids being passed to the query with quotes - I went into psql to test a few queries and this is successful:
SELECT "microposts".* FROM "microposts" WHERE "microposts"."id" IN (1,2,3);
while this fails:
SELECT "microposts".* FROM "microposts" WHERE "microposts"."id" IN ('1,2,3');
And the spec error is coming from an empty array being passed, equivalent to this, which also fails:
SELECT "microposts".* FROM "microposts" WHERE "microposts"."id" IN ('');
Can anyone who is familiar with PostgreSQL syntax tell me how to rewrite the method definition to fix this issue?
The current method in micropost.rb looks like this:
def self.from_users_followed_by(user)
followed_user_ids = user.followed_user_ids.join(', ')
where("user_id IN (?) OR user_id = ?", followed_user_ids, user)
end
And the call from `users.rb' looks like this:
def feed
Micropost.from_users_followed_by(self)
end
Holy crap, I actually figured this out myself. Just had to remove the join in the method definition:
def self.from_users_followed_by(user)
followed_user_ids = user.followed_user_ids
where("user_id IN (?) OR user_id = ?", followed_user_ids, user)
end
user.followed_user_ids.join(', ') produces this: "1, 2, 3"
while
user.followed_user_ids produces this: 1, 2, 3
which is what I wanted.