Rails 3 update_all with condition in console - ruby-on-rails-3

I have a Rails 3.2.14 app with a Facility model and I need to update the region_id in the Facility model based on a field called facility_name.
So I'm trying to update all Facilities where facility_name starts with DFW.
In the console I tried this:
Facility.where("facility_name: ilike 'DFW'")
This gives me nil or a 0 record return.
I'd like to be able to do something like this to update the region_id in the Facility model:
Facility.where("facility_name: ilike 'DFW'").update_all(region_id: '1')
But this doesn't work because my where method reports a 0 count even though there are plenty of records with the facility_name beginning with DFW.
Is my syntax wrong or is this not possible to do in Rails 3? If not, how would I go about updating over 100 records with this region id without doing it using crud/rails_admin?
I asked a similar question on how to use update_all but it didn't cover the conditional part. Hope this is not considered a duplicate.

It looks like you're kinda mixing up syntax.
When you put a where condition in a string, you need to conform to the syntax of your database adapter. So for postgres which has ilike, you need to do:
Facility.where("facility_name ilike 'DFW'")
The colon is used when you pass a hash instead, but one can't do like statements:
Facility.where(facility_name: 'DFW')
Note that if you want the ilike to check for any rows that contain that value in the column, you need trailing & leading percent signs.
Facility.where("facility_name ilike '%DFW%'")
From there you can perform the update_all

Related

SQL query equality comparison with special character that is equal to everything

I am writing a python script that gets info from a database through SQL queries. Let's say we have an SQL array with information about some people. I have one query that can retrieve this information about a specific person whose name I pass as an argument to the query.
(" SELECT telephone FROM People_info WHERE name=%s " % (name))
Is it possible to pass as an argument a special character or something like that will return me the telephone for all the names? Meaning something that when I compare with every name the result will be equal? I want to use only one query for all the cases (either if I want the info about one person or all of them)
You can edit the SQL code in
SELECT telephone FROM People_info WHERE name=nvl(%s, name)
and pass null if you want to get all the records
Notice that this will never get the records where name is null, but I suppose this is not a problem.
You can use LIKE and the wild card % which matches no, one or any number of any characters.
SELECT telephone
FROM people_info
WHERE name LIKE '%';
However, it won't show records where name IS NULL.
Maybe the optimizer is smart enough to see, that this actually equivalent to a WHERE name IS NOT NULL and uses an index, if there is one. But maybe it don't see it, then this may come as higher price than necessary. So I'd rather change the WHERE clause (or completely omit it, if I wanted all records) in the application to what I actually want, then use such tricks.

issues related find_by_sql in rails

I am using Rails 4 and I need to use find_by_sql in my active record model.Now I am facing two serious problems. First one is that it does not give me a particluar data whether it is giving #Employee:0x0000000b2a1718 as result. My model name is Employee and tbale name is employees. I am using pg.
Please tell me is there any solution.
Second problem is that how can I write any rails variable with in the sql query used in find_by_sql. For example I want to execute find_by_sql("select firstname from employee where id=#var"), where #var is a ruby variable.
The actual query I need to execute is select firstname from employee where comapact_string like %#var% using find_by_sql.
There's degrees of customization when making a query. The simplest form is where you can use the built-in finders:
Employee.where(id: #var).pluck(:first name)
That will do a direct match, and if one's found, give you the first_name column value. No model is produced with pluck.
If you want to do an approximate match with LIKE you write out the WHERE clause more formally:
Employee.where('id LIKE ?', "%{#var}%").pluck(:first_name)
It's rare you need to write out an entire query with find_by_sql, but if you do you must be extremely cautious about what data you put in the query. It's strongly recommended to use placeholder values whenever possible, and if you absolutely must bypass this, escape everything no matter the source.

Rails / SQL: Find attributes with same value but different capitalization

This may be really basic, but I can't think of how to write a SQL query that would find strings that have the same characters but different capitalization.
The context I'm working on is a Rails 3.2 app. I have a simple Tag model with a Name attribute. I've inherited data for this model that did not store values case-insensitively, so some users input things like "Tree" while others input "tree" and now we have two tags that really should be one.
So, I'd like to do a query to find all these pairs so that I can go about merging them.
The only thing I can think of so far is to write a rake task that loops through them all and checks for matching values... something like:
pairs = []
Tag.all.each do |t|
other = Tag.where( 'name LIKE ?', t.name )
pairs << [t, other] if other
end
However, I'm not sure the above would work, or that it makes sense performance-wise. Is there a better way to write a SQL query that would find these matching pairs?
There is a question similar to this here
What you can do is take that answer a create a method in your model to do a case insensitive search. From what i've experience however is that ActiveRecord already does case insensitive search but just in case:
def self.insensitive_find_by_tag_name(name)
Tag.where("lower(name) = ? ", name.downcase)
end
and then to remove duplicate entries, you can do something like this
Tag.transaction! do
tags = Tag.insensitive_find_by_tag_name(name)
tags.last(tags.length() - 1).each do |tag|
tag.destroy
end
end
Call transaction just in case anything fails so the database will rollback. Grab all tags with the same name, then delete any extra entries. If you want the remaining tag entry to be lower case then you can do
tag = tags.first
tag.name = tag.name.downcase
tag.save!
I'm not super good at SQL, but I researched this a bit and found out that using the COLLATE clause can be used to make string operations case sensitive in SQL. (typically select distinct operations are case insensitive.)
so maybe you could try:
select distinct (name) COLLATE sql_latin1_general_cp1_cs_as
FROM (
... blah blah blah
Here is some documentation on collate:
http://dev.mysql.com/doc/refman/5.0/en/charset-collate.html
(assuming you're using mysql I guess)
Alternatively you could also reconfigure your database to be case sensitive via collate also. Then your current query might work unaltered
(assuming you have administrative permissions and ability to reconfigure)
You should use upper() or lower() functions to convert the names all to lower or upper case.
SELECT DISTINCT upper(name)
Or:
SELECT DISTINCT lower(name)
Source: http://www.postgresql.org/docs/9.1/static/functions-string.html
Another option (better for maintainability of code) is to use the CITEXT type, but to do this you have to modify your table structure: http://www.postgresql.org/docs/9.1/static/citext.html

Ruby on Rails: getting the max value from a DB column

Currently I can make the straight-up SQL query on my DB:
SELECT MAX(bar) FROM table_name
And it returns with the max value in that table. When I make what I consider to be an equivalent call in Rails, however, it does not work. I am calling:
Bar.all(:select => "Max(bar)")
This simply returns with:
[#<Bar >]
In the column I'm calling on is a series of identifying numbers, I'm looking for the largest one. Is there some other way of accessing this in Rails?
Assuming your model name is Bar and it has a column named bar, this should work:
Bar.maximum(:bar)
See the excellent Rails Guides section on Calculations :: Maximum for more info.
one more way
Bar.select("Max(bar) as max_bar").first.max_bar

not on a query in RoR

In Ruby on rails 3 I want to query on a has_many field of a model as follows:
#project.items.where(:status => 1)
The problem is I'm trying to get the exact opposite result than this. What i want is all items of #project where the status is not 1. Been looking for the answer to this for a while, anyone?
There are many ways to accomplish what you are trying to do, however, some are better than others. If you will always be searching for a hardcoded number (i.e. 1 in this case), then the following solution will work:
#project.items.where('status != 1')
However, if this value is not hard-coded, you are openly vulnerable to SQL injection as Rails will not (cannot) escape this kind of query. As a result, it is preferred among Rails developers to user the following syntax for most custom conditions (those that can't be constructed via Hash):
#project.items.where(['status != ?', 1])
This syntax is slightly confusing, so let me go over it. Basically you are providing the where clause an Array of values. The first value in the array is a String representing the query you want executed. Anywhere you want a value in that string, you place a ?. This serves as a placeholder. Next, you add an element for every question mark in you query. For example, if I had the following:
where(['first_name = ? AND last_name = ?', params[:first_name], params[:last_name]]
Rails will automatically match these up forming the query for you. In that process, it also escapes potentially unsafe characters, preventing injection.
In general, it is preferred to use the Array syntax, even for a hardcoded value. I've been told that pure string conditions in Rails 3.5 will raise a warning (unverified), so it doesn't hurt to get in the process of using the Array syntax now.