Where query with Time.now - ruby-on-rails

I want to achieve the following:
Model.where("asdasd = ? AND to <= ?", nil, Time.now).each do |model|
I get the following error:
ActiveRecord::StatementInvalid: SQLite3::SQLException: near "to": syntax error: SELECT "bla".* FROM "table" WHERE (asdasd = NULL AND to <= '2015-11-09 10:18:14.777643')
I also use the same in another controller, where I get the same error. What would be the correct way to achieve what I want? I am also quite sure that it worked already like that, could there be any other thing which causes this issue?
Thanks!!!

TO is an SQL keyword, and needs to be quoted in a query. the list of SQLite keywords is avaiable in the SQLite documentation.
Other database engines have similar (but not identical) rules and lists of keywords, so if you change from SQLite then check the rules for whatever the new engine is.

Related

ActiveRecord update error - illegal zero-length identifier

I'm running simple Rails + ActiveRecord program, where I want to take records from the database, where column "transfered_at" is null, and update it with the current time.
orders_ora = Orders.where(transfered_at: nil)
orders_ora.each do |order_ora|
puts order_ora.name
order_ora.update(transfered_at: Time.now)
end
However, it does not allow me to do that. Here is the error that I'm getting:
OCIError: ORA-01741: illegal zero-length identifier: UPDATE
"ORDERS" SET "TRANSFERED_AT" = :a1 WHERE
"ORDERS"."" IS NULL (ActiveRecord::StatementInvalid)
What am I missing?
Edit: I need to use this inside the loop because I'm doing other calculations inside it. And time format does not seems to be the problem, because I'm trying to update another column which type is "number", and I'm getting the same error.
If I try to do it like this:
order_ora.inspection_id = 333
order_ora.save
it also gives the same error as before.
Why do you loop through the results? You can do it in a single query:
Orders.where(transfered_at: nil).update(transfered_at: Time.now)
What could be a problem is that the Time.now is not in the correct format for your table? Use strftime in that case:
Orders.where(transfered_at: nil).update(transfered_at: Time.now.strftime('%H:%M') )
I found answer to this myself, it was not related to the code.
The problem was that my table did not have a PK, and it looks like ActiveRecords uses it to generate SQL statements.

Rails 3 - .each works, .find_each fails -> ActiveRecord::JDBCError: ERROR: operator does not exist: character varying >= integer

I've got a lot (+100,000) of records I'm trying to process through a query.
I was using something like:
BigRecordPull.where(name: ['x','y','z']).each { |record| do_some_action record }
Because this isn't good from a memory management perspective, I wanted to instead use find_each as outlined here so now the code looks like this:
BigRecordPull.where(name: ['x','y','z']).find_each { |record| do_some_action record }
The issue is when I go to fire the code I get the following error:
ActiveRecord::JDBCError: ERROR: operator does not exist: character varying >= integer
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
If I review the SQL query created in the logs I get back something like:
SELECT "big_record_pull".* FROM "big_record_pull" WHERE "big_record_pull"."name" IN ('x','y','z') AND ("big_record_pull"."name" >= 0)
ActiveRecord seems to add the part, 'AND ("big_record_pull"."name" >= 0)' and that seems to be what's causing the problem. Name in this example is a varchar. The extra wrinkle is I don't control the postgresql db my rails project plugs into so I can't just re-run a migration to try and fix this issue. I'm hoping there's some sort of work around.... I'd like to avoid running raw SQL.
Extra info
In the example above, big_record_pull.name is also a foreign_key
Ok, the problem was related to a gem: composite_primary_keys-5.0.14.gem.
Solution was found, here
See lib/composite_primary_keys/relation/batches.rb:28:in `find_in_batches'
Change this block to:
self.primary_key.each do |key|
condition = case relation.columns_hash[key.to_s].type
when :string
table[key].not_eq ''
when :integer
table[key].gteq start
end
relation = relation.where(condition)
end

active record how do I specify a column after a join?

I'm trying to make an sql query using activerecord and I'm having a hard time specifying a specific column from multiple joined tables.
for instance in sql
select go.id, sequence.name, sequence.id from sequence join (goterms,...) on ...
this is not beautiful sql but my point is that I'm able to specify which .id I want returned
in activerecord I'm doing this:
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa)
.select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname,:read_depth, :name)
.distinct
I want to be able to get id from :Goterm but :Taxa and :Foreigndb also use id as a column in the database so i'm getting uninformative errors that I assume stem from this issue when I do the following.
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa)
.select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname,:read_depth, :name,:id)
.distinct
What is the correct way to just specify that I want Goterm.id?
edit - Here is the error:
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'Goterm.id' in 'field list'
when I run:
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass,:genus, :interpro_desc,:description,:dbname, :read_depth, :name,'Goterm.id').limit(5).offset(0).dresults = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname, :read_depth, :name,'Goterm.id').limit(5).offset(0).distinct
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass, :genus, :interpro_desc,:description,:dbname,:read_depth, :name, 'sequences.id')
.distinct
It turns out that ilan's answer is correct, however be sure that everything is lower case. I was using 'Goterm.id' to make the selection when it needs to be 'goterm.id'
If anyone else runs into this, I also ran into difficulties grabbing the goterm.id data out of the returned query objects. Each time I called object.id on that return set it would give me something different from what I was expecting. I think the attribute I was expecting was being obscured by something else. To get the data I needed I did the following:
results = Sequence.joins(:Foreigndb,:Goterm,:Taxa).select(:header,:taxaclass, :genus,:interpro_desc,:description,:dbname,:read_depth, :name).distinct
firstRes = results[0]
firstRes.attributes['id']

Validating SQL in where clause

I have a situation where I need to allow building up of SQL manually from a form. I have something like this:
SomeModel.where("id in (#{custom_sql})")
where custom_sql is a select statement like so:
SELECT u.id FROM some_model u WHERE country_iso = 'AU'
I want to be able to catch the StatementInvalid exception that is thrown when there is invalid SQL in the where clause, but I cannot figure out how to do so.
begin
SomeModel.where("id in (#{custom_sql})")
rescue
puts "Error"
end
But it keeps falling through without an error. Yet in rails c, when I do User.where("id in (#{custom_sql})"), it will correctly error. Any ideas?
Check the validity of your SQL statement using ActiveRecord::Base.connection.execute. It will throw an error if your statement is invalid.
begin
ActiveRecord::Base.connection.execute custom_sql
User.where("id in (#{custom_sql})")
rescue
puts "Error"
end
First of all your example is unclear or misleading (probably due to your efforts to mask your actual model names)
Because if you really wanted to run the scenario you are proposing, your resulting query would be
select * from some_model where id in (select u.id from some_model u where country_iso = "AU"
(ignoring the fact that your country_iso field is ambiguous) You are just running
SomeModel.where country_iso: "AU"
So you'll need to refine your example and properly illustrate your problem, because while #zeantsoi suggests a way to help you validate your statement(s), I agree with #phoet that you are probably approaching the situation incorrectly.
firstly, this is sql injection at it's best. you should reconsider whatever you want to accomplish.
secondly, User.where returns a relation. relations are lazy. lazy statements are not yet executed. so if you are doing User.where(...).all this should help.

Rails: Getting column value from query

Seems like it should be able to look at a simple tutorial or find an aswer with a quick google, but I can't...
codes = PartnerCode.find_by_sql "SELECT * from partner_codes where product = 'SPANMEX' and isused = 'false' limit 1"
I want the column named code, I want just the value. Tried everything what that seems logical. Driving me nuts because everything I find shows an example without referencing the actual values returned
So what is the object returned? Array, hash, ActiveRecord? Thanks in advance.
For Rails 4+ (and a bit earlier I think), use pluck:
Partner.where(conditions).pluck :code
> ["code1", "code2", "code3"]
map is inefficient as it will select all columns first and also won't be able to optimise the query.
You need this one
Partner.where( conditions ).map(&:code)
is shorthand for
Partner.where( conditions ).map{|p| p.code}
PS
if you are often run into such case you will like this gem valium by ernie
it gives you pretty way to get values without instantiating activerecord object like
Partner.where( conditions ).value_of :code
UPDATED:
if you need access some attribute and after that update record
save instance first in some variable:
instance=Partner.where( conditions ).first
then you may access attributes like instance.code and update some attribute
instance.update_attribute || instance.update_attributes
check documentation at api.rubyonrails.org for details

Resources