empty or null field check with postgres query in rails - ruby-on-rails

I am trying to check two condition with case in posgtres query, in my table one field may have two values either will be empty or will be single quote('') so i tried this query but it didn't execute
CASE WHEN (items.item_code is NULL OR items.item_code = '') THEN
items.name::text ELSE items.item_code::text END as item_code
Error like:
PG::Error: ERROR: syntax error at or near ")" LINE 1: ...HEN
(items.item_code is NULL OR items.item_code = ) THEN ite..

you have problem with quotes in ruby, not in sql statement.
try changing to:
CASE
WHEN (coalesce(length(items.item_code),0) + length(items.item_code)) < 1
THEN items.name::text ELSE items.item_code::text
END as item_code
the code above does same condition check as yours, buta voids using quotes. I suppose your could should be smth like:
CASE WHEN (items.item_code is NULL OR items.item_code = \'\') THEN
items.name::text ELSE items.item_code::text END as item_code

Related

undefined method `empty?' for #<PG::Result:0x007fcc82900a78>

We migrated our database from sqlite3 to postgreSQL. Now, at the following line, we get an error:
def self.get_table_id(id)
sql = "SELECT id FROM configtables WHERE parent = 'check' AND parentid = " + id.to_s
results = connection.execute(sql)
return nil if results.empty? # here's where the error happens
return results[0][0]
end
I have less knowledge of Ruby and ActiveRecords and with postgreSQL as well. Is the value in results a postgres-object, or whats #<PG::Result:0x007fcc82900a78> and what was it with the sqlite3 database?
This function is one of a few with raw sql-strings.
empty? is not defined for PG::Result:
PG::Result.instance_methods.include?(:empty?)
#=> false
To use empty? you should convert the result to an instance of Array:
results.to_a.empty?
Seems like you should "fetch" actual results from PG::Result object.
One way of doing this could be calling to_a
Try the following:
sql = "SELECT id FROM configtables WHERE parent = 'check' AND parentid = " + id.to_s
results = ActiveRecord::Base.connection.execute(sql).to_a
...

undefined method 'exec_prepared' on Rails 4 postgresql query

Every time, I submit a form supposed to create a Deal and sending a very high nb of Prizes (>200K) to the Prize table using a transaction and raw postgresql, I have first the error 'undefined method exec_prepared' then if I reload the form then I get a new error 'ERROR: prepared statement 'xixie' already exists'.
I used this question wrong number of arguments (1 for 2..3) for Active Record postgresql query (Rails 4/postgresql 9.4) and Prepared Statement on Postgresql in Rails to create the following Postgresql query:
models deals.rb
CONNEXION = ActiveRecord::Base.connection.raw_connection
def create_prizes
Deal.transaction do
self.prize_number.times do |i|
st = CONNEXION.prepare('xixie', 'INSERT INTO prizes (deal_id) values ($1)')
values = [ { value: self.id} ]
st.exec_prepared('xixie', values )
st.close()
end
end
end
I have this problem in Local (not production) and I am not using any puma/unicorn. I do use Zeus and Guard.
Is it impossible with Rails4/postgresql prepared_statements to insert multiple rows at a time ?
How can I change the query to make it work ?
Also as Rails gives me ' ERROR: prepared statement 'xixie' already exists', I had to change multiple times the name of the prepared_statements but will they "live" forever? how can I "kill" them after I do all theses iterations trying to find the appropriate query.
EDIT
Updated the code after some proposed answer:
CONNECTION = ActiveRecord::Base.connection.raw_connection
def create_prizes
Deal.transaction do
self.prize_number.times do |i|
CONNECTION.prepare('mimiku', 'INSERT INTO deal_prizes (deal_id, created_at, updated_at) values ($1, $2, $3)')
CONNECTION.exec_prepared('mimiku', [ { value: self.id}, { value: '2009-01-23 20:21:13' }, { value: '2009-01-23 20:21:13' } ] )
end
# CONNECTION.close()
end
end
(added '2009-01-23 20:21:13' as Rails required created_at and updated_at for some reason).
I get this error:
ERROR: prepared statement "mimiku" already exists
Even if I change the name from 'mimiku' to 'somethingelse', I still get this type of error.
The prepare method returns a result according to the docs:
http://deveiate.org/code/pg/PG/Connection.html#method-i-prepare
Maybe try call exec_prepared on the connection object
connection = ActiveRecord::Base.connection.raw_connection
def create_prizes
begin
connection.describe_prepared('xixie')
rescue PG::InvalidSqlStatementName
connection.prepare('xixie', 'INSERT INTO prizes (deal_id) values ($1)')
end
Deal.transaction do
self.prize_number.times do |i|
connection.exec_prepared('xixie', [ { value: self.id} ] )
end
end
end
UPDATE: I reworked the code above to first check if a prepared statement exists. If it doesn't exist it creates it. Sorry I haven't realized it in the first place but you don't need to prepare a statement more than once. This is the actual benefit of such a statement, since it has to be only parsed once and can than be executed with different values, which is then much faster than a regular query.
As prepared statements last for the duration of the AR connection you only need to prepare it once.

Query multiple key values with Rails + Postgres hstore

I am trying to make a query to search for values in my hstore column properties. I am filtering issues by user input by attribute. It is possible to search Issues where email is X, or Issues where email is X and the sender is "someone". Soon I need to change to search using LIKE for similar results. So if you know how to do it with LIKE also, show both options please.
If I do this:
Issue.where("properties #> ('email => pugozufil#yahoo.com') AND properties #> ('email => pugozufil#yahoo.com')")
it returns a issue.
If I do this:
Issue.where("properties #> ('email => pugozufil#yahoo.com') AND properties #> ('sender => someone')")
Here I got an error, telling me:
ERROR: Syntax error near 'd' at position 11
I change the "#>" to "->" and now this error is displayed:
PG::DatatypeMismatch: ERROR: argument of AND must be type boolean, not type text
I need to know how to query the properties with more than one key/value pair, with "OR" or "AND", doesn't matter.
I wish to get one or more results that include those values I am looking for.
I end up doing like this. Using the array option of the method where. Also using the suggestion from #anusha in the comments. IDK why the downvote though, I couldn't find anything on how to do something simple like this. I had doubt in formatting my query and mostly with hstore. So I hope it helps someone in the future as sure it did for me now.
if params[:filter].present?
filters = params[:filter]
conditions = ["properties -> "]
query_values = []
filter_query = ""
filters.each do |k, v|
if filters[k].present?
filter_query += "'#{k}' LIKE ?"
filter_query += " OR "
query_values << "%#{v}%"
end
end
filter_query = filter_query[0...-(" OR ".size)] # remove the last ' OR '
conditions[0] += filter_query
conditions = conditions + query_values
#issues = #issues.where(conditions)
end

.where.not with empty array

I have a problem trying to work with a NOT IN query (using Rails 4/Postgres, for reference) in an elegant way. I'm trying to get a list of all objects of a certain model that don't show up in a join table for a certain instance. It works , when you try a NOT IN query with an empty array, it throws an error because you can't look for NOT IN NULL.
The below code now works, but is there a better way than to use an unintuitive conditional to make a pseudo-null object?
def characters_selected
self.characters_tagged.pluck(:name)
end
def remaining_characters
characters = self.characters_selected
characters = ["SQL breaks if this is null"] if characters.empty?
# this query breaks on characters_selected == [] without the above line
Character.where("name NOT IN (?)", characters )
end
This is the ActiveRecord way:
def remaining_characters
characters = self.characters_selected
Character.where.not(:name => characters)
end
When characters.empty? the where clause becomes "WHERE (1=1)".

dynamic query for different values rails 4 activerecord

Here is the query I am trying in my controller
query = []
if id
query = "category_id: #{id}"
end
#posts = Post.where(query)
But throwing error as ERROR: syntax error at or near ":"
Why this is not working any other way to do it
if id
query << {sub_category_id: id}
end
if test
query << {test_id: test}
end
#posts = Post.where(query)
Is there any way of doing like this
Change query to a hash instead of string:
if id
query = { category_id: id }
end
#posts = Post.where(query)
The reason query = "category_id: #{id}" did not work is because the supplied string is literally used in the query generated by ActiveRecord, i.e. your select query will have category_id: 1 (assuming id is 1) in the where clause. And this is not a valid SQL syntax.
Please read on how you can use strings in conditions following this link. Thanks to #RustyToms for suggesting the link.
Update: ( Add extra conditions to the query hash )
if id
query[:sub_category_id] = id
end
if test
query[:test_id] = test
end
#posts = Post.where(query)
Another way to do this:
#posts = Post.scoped
#posts = #posts.where(category_id: id) if id
(in case you're playing codegolf)
Edit: (this is definitely a side note that isn't at all relevant)
Your original solution relies on one of my least favorite features of Ruby. Consider the following code:
if false
a = 4
end
puts a
I would expect the puts a to fail with a NameError (undefined local variable "a"), but no! The Ruby parser hits a = and then initalizes its value to nil. So, despite the fact that there is no way for the innards of that if statement to run, it still impacts the other code.

Resources