Like clause with Rails 3 and Sqlite - ruby-on-rails-3

I have a users table with name and surname and a search form with only a full_name field. How can I get it working?
I tried with this simple code:
where_clause = "(name + ' ' + surname) LIKE ?"
# page is a will_paginate method
#users = User.where([where_clause, "%#{params[:full_name]}%"]).page params[:page]
The above code produces:
SELECT "users".* FROM "users" WHERE ((name + ' ' + surname) LIKE '%test%') LIMIT 30 OFFSET 0
... which gives no results! Why?
I think the problem relies in the concatenation, but I can't see any alternatives. In fact I can't modify the select clause (i.e. "*, (name + ' ' + surname) AS full_name") because the page method doesn't work with active record find, and will_paginate methods (i.e. page or paginate) seems not to support conditions any more.

Try using:
where_clause = "(name || ' ' || surname) LIKE ?"

Related

Update query with variable

Is it possible to update a variable with a concatenation of variables(columns of VARCHARS2)?
UPDATE ARTICLE
SET DESCRIPTION = (CPV_DESCRIPTION + '/' LEVEL1_DESCRIPTION + LEVEL2_DESCRIPTION+LEVEL3_DESCRIPTION)
WHERE ID_ARTICULO = 209;
UPDATE ARTICLE
SET DESCRIPTION = concat(CPV_DESCRIPTION,'/',LEVEL1_DESCRIPTION,' ',LEVEL2_DESCRIPTION' 'LEVEL3_DESCRIPTION)
WHERE ID_ARTICULO = 209;
Both cases it gives me an error.
As mentioned by #a_horse... concat() function only takes 2 parameters. When you specify more that 2 parameters to be concated, you need to use || operator. Also + is a logical operator in Oracle unlike its used in Java for concatenation. Try this:
UPDATE ARTICLE
SET DESCRIPTION = CPV_DESCRIPTION
|| '/'
||LEVEL1_DESCRIPTION
||' '
||LEVEL2_DESCRIPTION
||' '
||LEVEL3_DESCRIPTION
WHERE ID_ARTICULO = 209;

Why doesn't this GROUP BY query work?

I'm querying my Access table with this query:
SELECT (VIN&' '&Make&' '&Model&' '&CarYear&' '&ExColor&' '&InColor&' ')as CarDescript
FROM TestTable
WHERE (WorkOrderNumber='$workorder')
GROUP BY AssignedEmp;
But a similar type of query works just fine in this SQL Fiddle
Even if I replace the long (VIN&' '&....) with VIN it still doesn't work.
EDIT: Schema of the table is
WorkOrderNumber - Priority - JobStage - WorkItem - AssignedEmp - DueDate - VIN - Make - ... - InColor
In general use + instead of & for SQL. (Access will allow this however).
In a group by you need to pick which one in the group to use (if you are using mysql like your example it just picks a random one, see this fiddle) so to fix this in the general case for your example:
SELECT (max(VIN) + ' ' + max(Make) + ' ' + max(Model) + ' ' + max(CarYear) + ' ' + max(ExColor) + ' ' + max(InColor) + ' ')
as CarDescript
FROM TestTable
WHERE WorkOrderNumber='$workorder'
GROUP BY AssignedEmp;

Postgres SELECT a concat field and ILIKE it in Rails

Pretty simple, trying to do this
SELECT (artist_name || ' ' || name) as full_name FROM "songs" WHERE "songs"."working" = 't' AND (full_name ILIKE('%Jack Beats%')) AND (full_name ILIKE('%Epidemic%')) AND (full_name ILIKE('%Dillon Francis%')) ORDER BY songs.published_at asc LIMIT 1
But I get
ActiveRecord::StatementInvalid: PG::Error: ERROR: column "full_name" does not exist
I've tried adding the table name before the stations with no effect.
As sub_stantial mentions in the comments, you can't reference an alias from a SELECT in your WHERE clause. You can use a derived table as dwurf suggests but derived tables in Rails are a bit messy. You could expand your concatenation inside your WHERE instead:
Song.where(:working => true)
.where("artist_name || ' ' || name ILIKE ?", '%Jack Beats%')
.where("artist_name || ' ' || name ILIKE ?", '%Epidemic%')
.where("artist_name || ' ' || name ILIKE ?", '%Dillon Francis%')
.order('songs.published_at asc')
.limit(1)
And if you're doing this sort of thing a lot, a named scope might be useful:
class Song < ActiveRecord::Base
#...
def self.full_name_like(name)
where("artist_name || ' ' || name ILIKE ?", "%#{name}%")
end
end
and then:
Song.where(:working => true)
.full_name_like('Jack Beats')
.full_name_like('Epidemic')
.full_name_like('Dillon Francis')
.order('songs.published_at asc')
.limit(1)
If your application is going to be doing a lot of ILIKE searches like this then you might want to look into a full-text search system: LIKE queries lead to table scans and table scans lead to sadness.
You can't reference a column alias in a where clause. The correct way to write this query is:
SELECT
(artist_name || ' ' || name) AS full_name
FROM "songs"
WHERE "songs"."working" = 't'
AND ((artist_name || ' ' || name) ILIKE('%Jack Beats%'))
AND ((artist_name || ' ' || name) ILIKE('%Epidemic%'))
AND ((artist_name || ' ' || name) ILIKE('%Dillon Francis%'))
ORDER BY songs.published_at ASC
limit 1
;
sub_stantial's approach would look more like this:
select full_name
from (
SELECT
(artist_name || ' ' || name) AS full_name
FROM "songs"
WHERE "songs"."working" = 't'
ORDER BY songs.published_at ASC
)
WHERE (full_name ILIKE('%Jack Beats%'))
AND (full_name ILIKE('%Epidemic%'))
AND (full_name ILIKE('%Dillon Francis%'))
LIMIT 1
;
Performance of these two queries is about the same (pretty rubbish) as they both have to do a full table scan to build the full_name column then sort the results. You might be able to add an index to "working" to speed up these queries.
Here's an sql fiddle in postgresql
Programatic Arel version
NOTE: This has not been fully tested for SQL injection.
class ApplicationRecord < ActiveRecord::Base
scope :fields_sentence_ilike, -> (*fields, term) {
sanitized_term = connection.quote("%#{term}%")
# InfixOperation.new(operator, left, right) => left operator right => concatenated_fiels ILIKE '%word%'
# NamedFunction.new(name, expression_nodes) => name(node0, node1, ...nodeN) => CONCAT_WS("columnA", "columnB", "columnC")
where(
Arel::Nodes::InfixOperation.new(
Arel::Nodes::SqlLiteral.new('ILIKE'),
Arel::Nodes::NamedFunction.new(
'CONCAT_WS', # CONCAT_WS concatenates strings using the first argument. In this case, an empty space.
[
Arel::Nodes::SqlLiteral.new("' '"), # CONCAT by empty space
*fields.map { |field|
# CONCATING any NULL fields results NULL (like multiplying any number by 0 equals 0). COALESCE to empty string.
Arel::Nodes::NamedFunction.new('COALESCE', [arel_attribute(field), Arel::Nodes::SqlLiteral.new("''")])
}
]
),
Arel::Nodes::SqlLiteral.new(sanitized_term)
)
)
}
end
Then a specific implementation for your Songs model
class Song < ApplicationRecord
scope :full_name_like, -> (full_name) { fields_sentence_ilike(:artist_name, :name, full_name) }
end
Usage
Song.full_name_like('Jack Beats')
.full_name_like('Epidemic')
.full_name_like('Dillon Francis')

Running a query and displaying result it in a TEdit

I have a TComboBox containing a list of names gathered from my database. Next to it is a TEdit that I intend on using for the purposes for displaying the ID number associated to each person.
Since firstName and lastName are separate fields within the table, but displayed together in the TCombobox I have written a small section to split the firstName and lastName into two separate variables:
pos := AnsiPos(' ', cbStudents.Text);
firstName := Copy(cbStudents.Text, 0, pos-1);
lastName := Copy(cbStudents.Text, pos+1, Length(cbStudents.Text));
Then I execute the SQL code:
try
query.Open;
query.SQL.Add('Select studentID');
query.SQL.Add('From student');
query.SQL.Add('Where firstName = ' + StrToQuote(firstName));
query.SQL.Add('And lastName = ' + StrToQuote(lastName));
editID.Text := query
finally
query.Free;
end;
Note: StrToQuote encapsulates the variable firstName and lastName with double quotes (" ")
The error that I am receiving is:
Argument out of range
What am I doing wrong? Thank you in advanced for the help.
Your code can not work. It opens the query first, then it sets the SQL query string. Instead of
try
query.Open;
query.SQL.Add('Select studentID');
query.SQL.Add('From student');
query.SQL.Add('Where firstName = ' + StrToQuote(firstName));
query.SQL.Add('And lastName = ' + StrToQuote(lastName));
finally
query.Free;
end;
use
// create or reset query here
query := ...
try
query.SQL.Add('SELECT studentID');
query.SQL.Add('FROM student');
query.SQL.Add('WHERE firstName = :firstname');
query.SQL.Add('AND lastName = :lastName');
// set parameter values here
query.Open;
// now transfer data from fields to the user interface (TEdit)
finally
query.Free;
end;
Your approach does not seam optimal for me (splitting Displayed Name), but your problem here would be accessing query.Fields[0].AsString after freeing the query.

Autosuggest search by full name

I've implemented an autosuggest search using jQuery, php and SQL server 2008. I'm looking for people by their name. The name of the person is divided in three fields 'nombres, 'apellido_paterno' and 'apellido_materno'. My autosuggest matches results where one of the three fields looks like the pattern in the input text.
$values = array(':x'=>$data['term'].'%',':y'=>$data['term'].'%',':z'=>$data['term'].'%');
$sql = "SELECT TOP 10 id_persona, nombres +' '+ apellido_paterno +' '+ apellido_materno AS value
FROM personas WHERE nombres LIKE :x OR apellido_paterno LIKE :y OR apellido_materno LIKE :z";
So my query is working fine if you search by name or lastname, however if you search by full name there are no matches. So, how do I add criteria to my query in order to bring full name matches?
Assuming all three are varchar fields, and you are querying a somewhat limited number of records, I would just do:
$values = array(':x'=>'%'.$data['term'].'%');
$sql = "SELECT TOP 10 id_persona, nombres +' '+ apellido_paterno +' '+ apellido_materno AS value
FROM personas
WHERE
nombres + ' ' + apellido_paterno + ' ' + apellido_materno LIKE :x";