What is the proper syntax for an Ecto query using ilike and SQL concatenation? - sql

I am attempting to make an Ecto query where I concatenate the first and last name of a given query result, then perform an ilike search using a query string. For example, I may want to search the database for all names that start with "Bob J". Currently, my code looks like this:
pending_result_custom_search = from result in pending_result_query,
where: ilike(fragment("CONCAT(?, '',?)", result.first_name, result.last_name), ^query)
(pending_result_query is a previous query that I am composing on top of)
This approach does not work and I continue to get an empty query set. If I perform the query doing something like this
query = "Bob"
pending_result_custom_search = from result in pending_result_query,
where: ilike(fragment("CONCAT(?, '',?)", "%Bob%", ""), ^query)
I get the correct functionality.
What is the proper syntax to get the first approach working properly?

I think in your case I would use only fragment, e.g.
query = "%" <> "Bob" <> "%"
pending_result_custom_search = from result in pending_result_query,
where: fragment("first_name || last_name ILIKE = ?", ^query)
That way you can shift the focus to PostGres and use its functions instead of worrying too much about the Ecto abstractions of them. In the above example, I used || to concatenate column values, but you could use PostGres' CONCAT() if you desired:
pending_result_custom_search = from result in pending_result_query,
where: fragment("CONCAT(first_name, last_name) ILIKE = ?", ^query)
Note that both examples here did not include a space between first_name and last_name. Also, I added the % characters to the search query before binding it.

Related

using wildcard and 'like' to compare contents of two columns in pgSQL

i have columns in two separate tables that i'm using in a join and subsequent update. i want to be able to see if one column has all of its content captured in a second column.
for instance, here is a sample of contents from each column:
city_table1 | city_table2
Portsmouth Portsmouth, New Hampshire, USA
i want to be able to have a where clause in a select statement that will match the two columns based on the contents in city_table1 (but i can't just do a left or right trim based on content variance), so i'm envisioning something like
where city_table1 like ('%' + city_table2 '%')
is my logic off here? should i referse the two fields in this where clause? i've tried this in postgres and got no results when i know it should work if i have the syntax right.
thank you!
Postgres uses || to concatenate strings. So:
where city_table2 like ('%' || city_table1 || '%')
Also, you have the comparison backwards. The shorter string is surrounded by the '%'.
And, this would be simpler with regular expressions:
where city_table2 ~ city_table1

how to query some characters in one field?

My database is Oracle 11g.
I want to do a in query in sql. The query criteria is to matched some of the characters of a field:
description
CWLV321900017391;EFHU3832239
CWLV321900017491;ERHU3832239
CWLV321900017591;ERHU3832239
CWLV321900017691;ERHU3832239
My query is like this:
select * from product where description in ('CWLV321900017391', 'CWLV321900017491');
It returns no records in result.
I expect the result like below:
description
CWLV321900017391;EFHU3832239
CWLV321900017491;ERHU3832239
How to get it by SQL?
thanks.
You are using IN to search for a partial string match in the description table. This is not going to return the results, as IN will only match exact values.
Instead, one way to achieve this is to use a LIKE operator with %:
select *
from product
where (description LIKE 'CWLV321900017391%' OR
description LIKE 'CWLV321900017491%');
The % at the end indicates that anything can follow after the specified text.
This will return any description that starts with CWLV321900017391 or CWLV321900017491.
Incidentally, if your search term occurs anywhere in the description field, you will need to use a % at each end of the search term:
description LIKE '%CWLV321900017391%' OR description LIKE '%CWLV321900017491%'
There are various ways to solve it. Here is one:
select * from product
where instr (description, 'CWLV321900017391') > 0
or instr (description, 'CWLV321900017491') > 0;
If you know you're always searching for the start of the description you can use:
select * from product
where substr (description, 1, 16) in ('CWLV321900017391','CWLV321900017491')
Also, there's LIKE or REGEX_LIKE solution. It depends really on what strings you're searching for.
Of course none of these solutions is truly satisfactory, and for large volumes of data may exhibit suck-y performance. The problem is the starting data model violates First Normal Form by storing non-atomic values. Poor data models engender clunky SQL.
You can try below way -
select * from product
where substr(description,1,instr(description,';',1,1)-1) in ('CWLV321900017391', 'CWLV321900017491')
I am opposed to storing multiple values in a delimited string format. There are many better alternatives, but let me assume that you don't have a choice on the data model.
If you are stuck with strings in this format, you should take the delimiters into account. You can do this using like:
where ';' || description || ';' like '%;CWLV321900017391;%'
You can also do something similar with regexp_like() if you want to look for one of several values:
where regexp_like(';' || description || ';',
'(;CWLV321900017391;)|(;CWLV321900017391;)'
)

Can I use Regular Expressions in USQL?

Is it possible to write regular expression comparisons in USQL?
For example, rather than multiple "LIKE" statements to search for the name of various food items, I want to perform a comparison of multiple items using a single Regex expression.
You can create a new Regex object inline and then use the IsMatch() method.
The example below returns "Y" if the Offer_Desc column contains the word "bacon", "croissant", or "panini".
#output =
SELECT
, CSHARP(new Regex("\\b(BACON|CROISSANT|PANINI)S?\\b"
)).IsMatch(wrk.Offer_Desc.ToUpper())
? "Y"
: "N" AS Is_Food
FROM ... AS wrk
Notes:
The CSHARP() block is optional, but you do need to escape any backslashes in your regex by doubling them (as in the example above).
The regex sample accepts these as a single words, either in singular or plural form ("paninis" is okay but "baconator" is not).
I'd assume it would be the same inline, but when I used regex in code behind I hit some show-stopping speed issues.
If you are checking a reasonable number of food items I'd really recommend just using an inline ternary statement to get the results you're looking for.
#output =
SELECT
wrk.Offer_Desc.ToLowerInvariant() == "bacon" ||
wrk.Offer_Desc.ToLowerInvariant() == "croissant" ||
wrk.Offer_Desc.ToLowerInvariant() == "panini" ? "Y" : "N" AS Is_Food
FROM ... AS wrk
If you do need to check if a string contains a string, the string Contains method might still be a better approach.
#output =
SELECT
wrk.Offer_Desc.ToLowerInvariant().Contains("bacon") ||
wrk.Offer_Desc.ToLowerInvariant().Contains("croissant") ||
wrk.Offer_Desc.ToLowerInvariant().Contains("panini") ? "Y" : "N" AS Is_Food
FROM ... AS wrk

SQL operator Like

IN SQL can you use the like operator to see if the first 2 letters of a value match the last 2 letters in another value ?
If a have attribute year and attribute phone number , i want to select these rows
which match the description above eg: year(1996) and phone number(9655771243);
No, at least not in a reasonable way. Most SQL engines support left() and right(), so you can do:
where right(year, 2) = left(phone_number, 2)
Databases that don't have other substring functions that do the same thing.
Using like, it would be something like:
where phone_number like right(year, 2) || '%'

MySql - autocomplete

I am creating an Ajax autocomplete application and would like know if there is an SQL query I can use for this purpose - e.g if someone types "p" I would like to retrieve all words beginning with "p", if they add "e" retrieve all words starting with "pe" - and continue like that.
Someone suggested the query below but I don't think it's what I'm looking for:
$query = "SELECT* FROM nametable WHERE names LIKE '$partialstring' ";
$query = "SELECT* FROM nametable WHERE names LIKE '$partialstring%' ";
I've added % only on the right side since you would like to have only the words that are beginning with the input letters.
However, please don't use this query until you've filtered it against SQL injections.
This should work:
$query = "SELECT * FROM nametable WHERE names LIKE '$partialstring%'"
The %is the wildcard character in SQL.
Edit: And yes, please sanitize that input.
Apart from regular special chars, you have to escape those with a special meaning in LIKE clauses.
I haven't fully tested the code but it should be something like this, assuming you are using PHP and the good old mysql extension (you don't mention):
$escape = '|';
$like = strtr(
mysql_real_escape_string($partialstring),
array(
'%' => $escape . '%',
'_' => $escape . '_',
$escape => $escape . $escape,
)
);
$query = "SELECT names FROM nametable WHERE names LIKE '$like%' ESCAPE '$escape' ORDER BY names LIMIT 10";
Also, don't forget to create an index on the names column.
Assuming you are sanitising that input, it should be something like:
$query = "SELECT* FROM nametable WHERE names LIKE '$partialstring%' ";
You can run a query like what Henning and others have written. And, yes, please sanitize the input to prevent injection attacks. I have also found this method to be rather slow when there are a lot of records. If you wish to match 'Bush' in the word 'GeorgeWBushSenior' ,the above said method wont work. In which case you have to use the query
select name from nametable where name like '%match%';
Try looking at the mysql full text query method. Its extremely handy in some cases.