Can't get delphi SQL LIKE to work with % - sql

I'm doing a school project and need to code a query to filter a dataset to certain variables. All my SQL works fine, except I can't get the LIKE statement to work with %-signs. I believe my syntax is wrong. Can anybody please tell me what I'm doing wrong. Thanks
The code:
qryMovie.SQL.Clear;
qryMovie.SQL.Add('SELECT * FROM Movies');
qryMovie.SQL.Add('WHERE Genre = ' + QuotedStr(genre));
qryMovie.SQL.Add('AND Price BETWEEN ' + minPrice + ' AND ' + maxPrice);
qryMovie.SQL.Add('AND Title LIKE %' + title + '%');
qryMovie.Open;
Error produced:
'Syntax error in query expression 'Genre = 'Action/Adventure'
AND Price BETWEEN 0 AND 200
AND Title LIKE %Star Wars%''

LIKE %Star Wars%
but you need
LIKE '%Star Wars%'
You need to quote % with ':
qryMovie.SQL.Add(' AND Title LIKE ''%' + title + '%''');
Anyway you should use binded parameters instead of concatenating SQL string. It is error-prone and could lead to SQL Injection attacks.

Related

Performance of an SQL query for finding users in database

I am developing an application and I am using Spring Data JPA for database manipulation.
I am implementing a feature for finding friends with a searchbar. The way it is supposed to work is that when you enter some characters, a search is performed in the database to find and display 10 users that match the characters (the first name starts with it, the last name starts with it and it also should work if someone enters the full name).
I have written the code and it works the following way:
#Query(nativeQuery = true,
value="SELECT * FROM users u WHERE (" +
"UPPER(first_name) like CONCAT(UPPER(:query),'%') OR " +
"UPPER(last_name) like CONCAT(UPPER(:query),'%') OR " +
"UPPER(CONCAT(first_name,' ', last_name)) like CONCAT(UPPER(:query),'%')" +
") LIMIT 10")
List<User> findByQueryLikeName(#Param("query") String query);
However, when I look at this query it really seems like it might not be the best performance-wise. I do not have a lot of knowledge about sql performance, but I think that because it combines 3 where statements with an OR operator, and also uses some functions like UPPER and CONCAT a lot. I am using PostgreSQL.
Can you please assess if this kind of query is going to perform well on a big number of records? Can you try and explain why / why not? Do you have any tips on how to improve it?
Thanks a lot!
I would rewrite the query like this:
SELECT * FROM users u
WHERE concat(' ', u.first_name,' ', u.last_name) ILIKE ' ' || :query || '%';
You'd have to create a trigram index to support this:
CREATE EXTENSION pg_trgm;
CREATE INDEX ON users USING gin
(concat(' ', u.first_name,' ', u.last_name) gin_trgm_ops);
As pointed out in comments it's probably so slow because you are using functions in the WHERE clause:
https://www.mssqltips.com/sqlservertip/1236/avoid-sql-server-functions-in-the-where-clause-for-performance/
Alternatively you could add to your entity another field fullName and update it in setFirstName() and setLastName() like this:
void setFirstName(String first){
this.fullName = first.toUpperCase() + " " + this.lastName.toUpperCase(); //TODO handle nulls
}
Then you could query by that fullName, which would be already uppercased, then uppercase you search string in java and have a simple like query:
public List<User> findByFullnameContaining(String searchText, Pageable pageable);

Pyodbc and Access with query parameter that contains a period

I recently found a bug with some Access SQL queries that I can't seem to track down. I have a fairly straightforward SQL query that I use to retrieve data from an access database that's "managed" in an older application (ie the data is already in the database and I have no real control over what's in there).
import pyodbc
MDB = '******.MDB'
DRV = '{Microsoft Access Driver (*.mdb)}'
PWD = ''
con = pyodbc.connect('DRIVER={};DBQ={};PWD={}'.format(DRV, MDB, PWD))
sql = ('SELECT Estim.PartNo, Estim.Descrip, Estim.CustCode, Estim.User_Text1, Estim.Revision, ' +
'Estim.Comments, Routing.PartNo AS RPartNo, Routing.StepNo, Routing.WorkCntr, Routing.VendCode, ' +
'Routing.Descrip AS StepDescrip, Routing.SetupTime, Routing.CycleTime, ' +
'Routing.WorkOrVend, ' +
'Materials.PartNo as MatPartNo, Materials.SubPartNo, Materials.Qty, ' +
'Materials.Unit, Materials.TotalQty, Materials.ItemNo, Materials.Vendor ' +
'FROM (( Estim ' +
'INNER JOIN Routing ON Estim.PartNo = Routing.PartNo ) ' +
'INNER JOIN Materials ON Estim.PartNo = Materials.PartNo )')
if 'PartNo' in kwargs:
key = kwargs['PartNo']
sql = sql + 'WHERE Estim.PartNo=?'
cursor = con.cursor().execute(sql, key)
# use this for debuging only
num = 0
for row in cursor.fetchall():
num += 1
return num
This works fine for all PartNo except when PartNo contains a decimal point. Curiously, when PartNo contains a decimal point AND a hyphen, I get the appropriate record(s).
kwargs['PartNo'] = "100.100-2" # returns 1 record
kwargs['PartNo'] = "200.100" # returns 0 records
Both PartNos exist when viewed in the other application, so I know there should be records returned for both queries.
My first thought was to ensure kwargs['PartNo'] is a string key = str(kwargs['PartNo']) with no change.
I also tried to places quotes around the 'PartNo' value with no success. key = '\'' + kwargs['PartNo'] + '\''
Finally, I tried to escape the . with no success (I realize this would break most queries, but I'm just trying to track down the issue with a single period) key = str(kwargs['partNo']).replace('.', '"."')
I know using query parameters should handle all the escaping for me, but at this point, I'm just trying to figure out what's going on. Any thoughts on this?
So the issue isn't with the query parameters - everything works as it should. The problem is with the SQL statement. I incorrectly assumed - and never checked - that there was a record in the Materials table that matched PartNo.
INNER JOIN Materials ON Estim.PartNo = Materials.PartNo
will only return a record if PartNo is found in both tables, which in this particular case it is not.
Changing it to
LEFT OUTER JOIN Materials ON Estim.PartNo = Materials.PartNo
produces the expected results. See this for info on JOINS. https://msdn.microsoft.com/en-us/library/bb243855(v=office.12).aspx
As for print (repr(key)) - flask handles the kwarg type upstream properly
api.add_resource(PartAPI, '/api/v1.0/part/<string:PartNo>'
so when I ran this in the browser, I got the "full length" strings. When run in the cmd line using python -c ....... I was not handling the argument type properly as Gord pointed out, so it was truncating the trailing zeros. I didn't think the flask portion was relevant, so I never added that in the original question.

SQL Inner Query In Replace Statement

I would like to replace a certain part of a columns field with something else. The only issue is that what I've tried doesn't work. I'm using HeidiSQL
This is a overview of the database:
Database Overview
What I would like to do is for each user_id with field_id 523 I would like to replace 'centraal-zorgportaal.nl/afbeeldingen/' with '/profiles/(for each user id here)/'.
So the end result example after running the query will look like this:
'/profiles/711/logo.gif', but then for each user with a diffrent logo.gif.
Note: Can't post more than two links so removed the http etc. in front.
This is the query I've tried and dind't work:
update wp_bp_xprofile_data
set value = replace( value,
'http://www.centraal-zorgportaal.nl/afbeeldingen/',
'/profiles/' +
(select user_id
from wp_bp_xprofile_data
where user_id = #n := #n + 1 n) +
'/')
where field_id = 523
(Table name is: wp_bp_xprofile_data)
This is the error message I received:
Error message:
Could anyone explain why this doesn't work, how to fix it and the best way to approach this problem?
In MySQL/MariaDB, you cannot refer to the table being modified. From your description, you seem to want something like this:
update wp_bp_xprofile_data
set value = replace(value,
'http://www.centraal-zorgportaal.nl/afbeeldingen/',
concat('/profiles/', user_id, '/')
)
where field_id = 523;

like case in inline query making error

My inline sql query is like this
DataSet ds = SqlHelper.ExecuteDataset(GlobalSettings.DbDSN, CommandType.Text,
"SELECT TOP 1000 [ID],[Project],[Owner],[Consultant],[Contractor],[Value],
[Level1], [Level2] ,[Status] ,[Category] ,[Country],[CreatedDate],
[CreatedByID], [CreatedByName]
FROM [DBname].[dbo].[tbl_Projects]
where [Category] like %#Category%
and Value=1000
and Country like'%Bahrain%'
order by CreatedDate",
new SqlParameter("#Category","oil") );
everything looks okay to me .But it throws an error
System.Data.SqlClient.SqlException: Incorrect syntax near 'Category'.
I believe it is something I had done wrong when using like query.
Can any one point out what went wrong?
I think this should work
... LIKE '%' + #Category + '%'
cf. T-SQL and the WHERE LIKE %Parameter% clause

NHibernate Criteria - How to filter on combination of properties

I needed to filter a list of results using the combination of two properties. A plain SQL statement would look like this:
SELECT TOP 10 *
FROM Person
WHERE FirstName + ' ' + LastName LIKE '%' + #Term + '%'
The ICriteria in NHibernate that I ended up using was:
ICriteria criteria = Session.CreateCriteria(typeof(Person));
criteria.Add(Expression.Sql(
"FirstName + ' ' + LastName LIKE ?",
"%" + term + "%",
NHibernateUtil.String));
criteria.SetMaxResults(10);
It works perfectly, but I'm not sure if it is the ideal solution since I'm still learning about NHibernate's Criteria API. What are the recommended alternatives?
Is there something besides Expression.Sql that would perform the same operation? I tried Expression.Like but couldn't figure out how to combine the first and last names.
Should I map a FullName property to the formula "FirstName + ' ' + LastName" in the mapping class?
Should I create a read only FullName property on the domain object then map it to a column?
You can do one of the following:
If you always work with the full name, it's probably best to have a single property
Create a query-only property for that purpose (see http://ayende.com/Blog/archive/2009/06/10/nhibernate-ndash-query-only-properties.aspx)
Do the query in HQL, which is better suited for free-form queries (it will probably be almost the same as your SQL)
Use a proper entity-based Criteria:
Session.CreateCriteria<Person>()
.Add(Restrictions.Like(
Projections.SqlFunction("concat",
NHibernateUtil.String,
Projections.Property("FirstName"),
Projections.Constant(" "),
Projections.Property("LastName")),
term,
MatchMode.Anywhere))
On the pure technical side i don't have an answer, but consider this:
since you are only have a single input field for the user to enter the term, you don't know if he is going to enter 'foo bar' or 'bar foo'... so i would recommend this:
ICriteria criteria = Session.CreateCriteria(typeof(Person));
criteria.Add(Expression.Like("FirstName",term, MatchMode.Anywhere) || Expression.Like("LastName",term, MatchMode.Anywhere));
criteria.SetMaxResults(10);