Ruby/Rails string case comparison issue's within postgres - ruby-on-rails

I have a CSV that has a string column called name, It has things like "3 months pasta".
I want to map this to an existing DB table. The DB record has it saved as "3 months Pasta".
If I try Food.where(name: row['name']) it will come up empty. because it is doing a direct string to string comparison between "3 months pasta" and "3 months Pasta".
I have tried this as well
Food.where('name LIKE ?', '%' + "3 months pasta" + '%')
Which did not work unless I uppercase the "p", what can I do to get the strings to match on both ends? I want to do a row['name'].parameterize.underscore to get it to a single case and single style and then doing the same from the DB and matching them. The issue is doing this could be costly converting all the names then doing the comparison.
Is there something that I could do to achieve this?

Try
Food.where("lower(name) = ?", row['name'].downcase)

Though the #Ursus’ answer is perfectly correct, I would go with native case insensitive search against DB:
Food.where('name = ? COLLATE utf8_general_ci', "3 months pasta")
ci in collation name stands for “case insensitive.”

Related

How can I write a Rails query to find phone number which are all saved with various formats

I'm using Rails 5.2.0
I am trying to write a query to find a phone number based off user input. However, the format of phone numbers saved in the database varies (e.g. (123)-456-7890, +1(123)-456-7890, +1 123456789, and so on). Is there any way I can format the records saved in my database in this query? I've thought of adding a second column to the table that would simply be formatted_telephone, but I have tens of thousands of records. Can I add a method in the User controller to update these records when they are fetched?
Here is what I have so far:
User.where("REGEXP_REPLACE(telephone, '[^[:digit:]]', '') ~* ?", "%#{input}%")
Right now this is still only returning phone numbers with this format: 1234567890.
Am I on the right track with this? Or is it not possible to format columns when querying?
Normally with a where clause and a regexp we are asking something like "find me everything that matches this regexp" but you are asking the DB for a phone number that matches "12035551212" and want the where clause to apply a regexp to every single phone number in the table while searching to match it. I guess you try something like (this can be streamlined but I'm breaking it down to make it easier to follow):
my_phone = '12035551212'
phone_arr = my_phone.split('')
#=> ["1", "2", "0", "3", "5", "5", "5", "1", "2", "1", "2"]
regx = '^\D?' + phone_arr[0] + '?' + '\D*' + phone_arr[1..-1].join('\D*') + '$'
#=> '^\D?1?\D*2\D*0\D*3\D*5\D*5\D*5\D*1\D*2\D*1\D*2$'
now you have a regexp that matches only your phone number regardless of format. So now you can try:
User.where('phone_number ~* ?', regx)
this should ask Postgres to match your very specific regexp based on the phone number you are searching for. This should get you what you need. But I would look at refactoring it.
In the long run I would standardize all numbers in the DB. You could add a phone_number_e164 column to Users and convert every one to the E164 format using a regexp. Then remove the old phone number column and rename the new one to phone_number. You would also need to add code to standardize any new numbers coming into the DB.
As a stop-gap measure you could also create a Postgres view that grabs the User records and applies regexp to the phone number to transform it to E164 format, and access that view instead of the User table.

How to capture regex first occurence and interpolate into string with postgreSQL

I'm trying to concatenate the digits from a string that starts with 'CityName' into a separate string. I have the concatenation part. My issue is being able to access the matches from the regex
I have a regex in rails that looks like /CityName\s*(\d+)/i. I'm super new to regex and it's hard for me to wrap my head around the docs. But I'm assuming that this regex will find any digits after the CityName case intensively. And then it's interpolated if it matches an attribute on my model.
regex = /CityName\s*(\d+)/i
if line_1 =~ regex
"C#{$1}"
...
end
But further along in the execution, it's slowing down because I have to iterate over a lot of records. I have a query in psql that will do that calculations that I need, however I'm having a hard time implementing this regex replacement. My attempts so far look like:
CASE
when addr.line_1 ~* 'CityName\s*(\d+)' then 'C' || regex_matches('CityName\s*(\d+)')[0]
...
I'm having a hard time finding a solution to grab the first occurrence of the regex match. Thanks for any tips :D
EDIT: I am trying to grab the digits after 'CityName' from a string if that string contains 'CityName'
Ultimately I need assistance with the regex and how to contactenate the digits with 'C'
Your question is a bit unclear. Are you trying to add the digits to your selection or to filter records based on them?
If you just want to select them:
Address.select(%q{(regexp_matches(addr.line_1, 'CityName\s*(\d+)'))[1] as digits})
.map(&:digits)
If you want to filter based on then:
Address.where(%q{addr.line_1 ~ 'CityName\s*(\d+)'}).map &:email
.map(&:line_1)
Also a few notes:
Selecting digits case intensively does not really make sense. Digits
does not have case.
PostgreSQL arrays start from 1 instead of 0.
It seems you need a subquery or a WITH query:
SELECT tbl1.col1, sum(...), min(...) FROM (SELECT ..., CASE ...yourregex stuff... END col1 FROM ...) tbl1 GROUP BY 1;
WITH tbl1 AS (SELECT ..., CASE ...yourregex stuff... END col1 FROM ...) SELECT t.col1, sum(...) FROM tbl1 t GROUP BY 1;
If you need them regulary, you can also create views from the query or create a temp table, then you can use it in queries later.
Got it! Was able to finally start to figure out the regex.
WHEN addr.line_1 ~* '(?i)CityName\s*(\d+)' THEN 'C' || (SELECT (regexp_matches(addr.line_1, '(?i)CityName\s*(\d+)'))[1])
The (?i) allowed for case insensitive matching for CityName and then the concatenation worked. Thank you #ti6on for pointing out the index difference with postgres :D

Ruby On Rails searching database for word

I am new to rails. I am trying to search a database in MySQL where the term I am searching may be one word in the column string. For example if the cell was "this is a very lovely day" then I would like to be able to call that object by searching for the word 'lovely'
Thank you.
You need to do a LIKE query. (i.e. foo LIKE %bar%) The % represents a wildcard operator. bar% would be "starts with bar" and %bar% would be "contains bar." Note that contains searches cannot use column indexes and will be slow.
Suppose you had a Day class with the attribute description. In that case, you would do
Day.where("description LIKE '%lovely%')
by using Arel
days = Day.arel_table
Day.where(days[:description].matches("%lovely%"))

Return date as year

I wrote this little search query:
User.where("strftime('%Y', birthday) = ?", 1994)
But somehow i get no search resuts although i now that i have several users with their birthday in 1994. In the Users Table birthday is defined as date
Now i have two ideas how i could solve my problem:
1.I could check what the result of "strftime('%Y', birthday) is for a specific user or the whole user collection. But i dont know the expression! Maybe you know the expression?
2.You know what i did wrong and you have an answer?
Thanks!
In Rails you can write the query like:
User.where("birthday BETWEEN '?-01-01' AND '?-12-31'",1994,1994)
See this post for why this kind of format is good performance-wise when compared to something that uses "YEAR": SQL query where() date's year is $year.
Your mileage may vary but I've gotten around some of these issues by querying the date column using it's underlying string format...
User.where("birthday like ?", "1994-%")
I'm too lazy to checkout sqlite's support for regexen but if you can use them then you could also try
User.where birthday: /^1994-\d{2}-\d{2}/
you should use something like
User.where("YEAR(birthday) = ?", 1994)
Ref:
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_year

Heroku/postgresql search

I have a database with names of cities that uses all different kinds of characters, from åäö to vietnamese signs. The place names are all in a capitalized format e.g. "New York" and "Aix En Provence".
My problem now is to try to search for these city names in Heroku which uses postgresql.
p = Place.where("upper(name) LIKE '%" + place_name_searched.to_s.upcase.tr('åäöüñï','ÅÄÖÜÑÏ') + "%'").first
This is the best I have come up with but it is only but a fix for åäö etc and doesn't catch all the 100+ different characters there is out there, e.g. "é". The solution is not to fill out that string any further.
A general problem is that upper(name) seems to translate everything fine but upcase can only handle english letters. So the correspoding search will be .where("TÄBY like 'TäBY') if place_name_searched = 'täby'.
So, how can I match postgresql entries such as "Täby" and "Jidd Ḩafş" to corresponding strings in downcase, entered by the user ("täby", "jidd hafs")?
It all works fine in my Mysql-version of the application but once I upload to Heroku it all fails.
Postgres has an extension called "ILIKE" for case insensitive pattern matching.
p = Place.where("upper(name) ILIKE '%" + place_name_searched.to_s.upcase.tr('åäöüñï','ÅÄÖÜÑÏ') + "%'").first
But please note this only works with Postgres, so you need to check which environment you are running on to decide if you would use this one instead of the regular one.

Resources