LINQ inserts 'ESCAPE N'~' in query - sql

When I examine the SQL query the Linq spits out, I noticed that it places a ESCAPE N'~' when doing a LIKE command. How do I get rid of this? It seems like the query takes twice as long with the ESCAPE is in the SQL.
Here is the LINQ
var SearchPhrase = "xyz";
var result = (from i in db.myTable
where i.col1.contains(SearchPhrase)
select i).toList();
When I look at the actual SQL it looks something like this:
SELECT
[Extent1].Col1
FROM myTable As [Extent1]
WHERE [Extent1].Col1 LIKE #p__linq__3 ESCAPE N'~'

Apparently,
var SearchPhrase = "xyz";
var result = (from I in db.myTabl
where i.col1.contains(SearchPhrase)
select I).toList();
will add ESCAPE N'~' in the underlying query.
However using a constant filter like the following, doesn't produce escape characters in the underlying query
var result = (from I in db.myTabl
where i.col1.contains("xyz")
select I).toList();
Which means, variable filters are escaped, while constants are not.
So, in this case, we need a variable to be used as a constant filter.
Using the following, shouldn't add any escape characters:
var SearchPhrase = "xyz";
var result = (from I in db.myTabl
where SqlMethods.Like(i.col1, string.Format("%{0}%", SearchPhrase))
select I).toList();
but this works only with LINQ to SQL.
The other alternative is to embed the variable value as a constant, which is done using the following as explained in the SO article

Linq to Sql use '`' as it's default escape character when doing like comparisons. It will only cause a problem if your string actually contains ~ characters.
Use SqlMethods.Like to override this.

If you use LINQ 2 Entities, use SqlQuery to remove the "~" character.
Just append the value to compare like an ordinary sql query.
For example:
var resultList = context.TableName.SqlQuery(
"SELECT * FROM TableName WHERE field LIKE '%" + fieldValue+ "%' ").ToList();

Related

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

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.

How to use regex replace in Postgres function?

I have postgres function in which i am appending values in query such that i have,
DECLARE
clause text = '';
after appending i have some thing like,
clause = "and name='john' and age='24' and location ='New York';"
I append above in where clause of the query i already have. While executing query i am getting "and" just after "where" result in error
How to use regex_replace so that i remove the first "and" from clause before appending it to the query ?
Instead of fixing clause after the fact, you could avoid the problem by using
concat_ws (concatenate with separator):
clause = concat_ws(' and ', "name='john'", "age='24'", "location ='New York'")
will make clause equal to
"name='john' and age='24' and location ='New York'"
This can be even simpler. Use right() with a negative offset.
Truncates the first n characters and you don't need to specify the length of the string. Faster, simpler.
Double quotes (") are for identifiers in Postgres (and standard SQL) and incorrect in your example. Enclose string literals in single quotes (') and escape single quotes within - or use dollar quoting:
Insert text with single quotes in PostgreSQL
Since this is a plpgsql assignment, use the proper assignment operator :=. The SQL assignment operator = is tolerated, too, but can lead to ambiguity in corner cases.
Finally, you can assign a variable in plpgsql at declaration time. Assignments in plpgsql are still cheap but more expensive than in other programming languages.
DECLARE
clause text := right($$and name='john' and age='24' ... $$, -5)
All that said, it seems like you are trying to work with dynamic SQL and starting off on the wrong foot here. If those values can change, rather supply them as values with the USING clause of EXECUTE and be wary of SQL injection. Read some of the related questions and answers on the matter:
https://stackoverflow.com/search?q=[plpgsql]+[dynamic-sql]+EXECUTE+USING
You do not need regex:
clause = substr(clause, 5, 10000);
clause = substr(clause, 5, length(clause)- 4); -- version for formalists
concat_ws sounds like the best option, but as a general solution for things like this (or any sort of list with a delimiter) you can use logic like (pseudocode):
delim = '';
while (more appendages)
clause = delim + nextAppendage;
delim = ' AND ';
If you want to do it with regular expression try this:
result = regexp_replace(clause, '^and ', '')

how to use a string that contain ' in SQL "IN" clause

i have a string value like 'Apple's'. i want to use this string in SQL "IN" clause like below query
select * from tbl_fruit where nm_fruit IN(''Apple's'','Orange');
how i can get the above query work correctly ?
Many Thanks,
Awais Afzal.
double the single quotes,
select * from tbl_fruit where nm_fruit IN ('Apple''s', 'Orange')
but if you do it on the application level, make sure you parameterized the query :)
I have found SQL correctly interprets the ASCII single-closed-quote (ALT 0146) as an apostrophe in searches while the "IN" treats it like any other character. Now I can search for 'Matt's Macintosh' using Matt(ASCII character 0146)s Macintosh" without messing up my list or the search.

MySQL query problem with 'like' and confusion

I need to use a string query to make a DB search for a C# program that interacts with MySQL server. What I want to find is a name that is 'like' one of my other variables (nameVar)
I have the following query in a C# program
string q = "SELECT *
FROM TABLE
WHERE name is like %?nameVar%";
As soon as execute the query in my program I get a syntax error telling me that syntax near
'like' is incorrect. As soon as I remove the "%" sign, it works fine.
I am confused, is mandatory to remove the % sign while building a query string?
Your parameter is replacing the ?nameVar part, including quotes. If the param is "TEST", your query gets presented as
string q = "SELECT *
FROM TABLE
WHERE name is like %'TEST'%";
As you can see, the % signs are out of place. either include them from the C# program into namevar, or change the query to
string q = "SELECT *
FROM TABLE
WHERE name is like '%' + ?nameVar + '%'";
you need to quote the query:
string q = "SELECT * from table where name is like '%?nameVar%'";
Strings in SQL need to be enclosed in single quotes:
string q = "SELECT *
FROM TABLE
WHERE name LIKE '%?nameVar%' ";
Also, there's no IS operator when using LIKE.
I think the correct syntax is:
SELECT * FROM table WHERE fields LIKE '%phrase%'
I think you have to leave out 'is'.
MySQL Pattern Matching

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.