Correct syntax of using MySQL LIKE? - mysql

I have query with a bunch of LIKE statenements. I want to optizimze/explain the query, which runs fine. However if I copy this:
SELECT a.*, p.ek, p.vk, p.waehrung, p.onlinepreis
FROM arts a USE INDEX (i_aktiv, i_iln, i_marke )
LEFT JOIN pls p ON
p.iln = a.iln
LEFT JOIN fbs zu
ON a.farbe = zu.farbe
WHERE a.aktiv = "ja"
AND (
a.artikelbezeichnung LIKE ?
OR a.artikelbezeichnung_lang LIKE ?
OR ( a.farbe LIKE '%decke%'
OR zu.systemfarbe LIKE '%decke%'
OR zu.systemfarbe_en LIKE '%decke%'
)
)
)
...
As parameters I want to add '%decke%' but MySQL keeps throwing an error, if I use the %%.
Any idea what I'm doing wrong?
The error I'm getting is:
you have an error in your SQL-syntax.... check near... %'%'decke%' at OR ( a.farbe LIKE '%decke%' ...

For wildcarded LIKE comparisons, you have to fake it:
WHERE somefield LIKE CONCAT('%', ?, '%')
wildcarded 'likes' are one place that parameterized queries fall flat on their faces.

Related

Getting different results from Spring JPA query vs raw SQL in console

I have the following SQL query which returns one result, as expected, when I run it in the MySQL console:
SELECT DISTINCT a.* FROM account a
INNER JOIN contact c ON a.id = c.accountId WHERE a.accountName LIKE '%test#test.com%'
OR a.id IN (SELECT e.accountId FROM environment e WHERE e.externalId LIKE '%test#test.com%'
OR e.name LIKE '%test#test.com%')
OR c.email = 'test#test.com'
I use the same query in my application code, yet zero results are returned:
#Query(value = "SELECT DISTINCT a.* FROM account a INNER JOIN contact c ON a.id = c.accountId WHERE a.accountName LIKE %?1% OR a.id IN " +
"(SELECT e.accountId FROM environment e WHERE e.externalId LIKE %?1% OR e.name LIKE %?1%) " +
"OR c.email = ?1", nativeQuery = true)
List<Account> findAccountByKeyword(String keyword);
I see the following SQL being generated, which looks fine to me:
select distinct account0_.id as id1_0_, account0_.createdBy as createdB2_0_, account0_.createdDate as createdD3_0_, account0_.lastUpdatedBy as lastUpda4_0_, account0_.updatedDate as updatedD5_0_, account0_.accountName as accountN6_0_, account0_.globalMessage as globalMe7_0_, account0_.isConsultingPartner as isConsul8_0_, account0_.isNonProfit as isNonPro9_0_, account0_.isSuspended as isSuspe10_0_, account0_.note as note11_0_, account0_.parentId as parentI12_0_, account0_.products as product13_0_, account0_.salesforceId as salesfo14_0_, account0_.type as type15_0_, account0_.typeShort as typeSho16_0_, account0_.usedProducts as usedPro17_0_
from account account0_ inner join contact contact1_ on (account0_.id=contact1_.accountId)
where account0_.accountName like ? or account0_.id in (select environmen2_.accountId from environment environmen2_ where environmen2_.externalId like ?
or environmen2_.name like ?)
or contact1_.email=?
Any ideas what could be going wrong here? I have verified that the value of keyword is correct so I'm at a complete loss what else I can try. Other questions regarding inconsistencies between native SQL and queries within Spring are all talking about problems with date types but I'm not even using dates here or anything dialect-specific.
Please let me know if you need more information and I will edit my question accordingly.
are your queries really the same? Like '%test#test.com%' in your Mysql and LIKE %?1% in your native SQL. I guess you lose the % before and after your parameters somewhere.
Replacing like %?1% with like CONCAT('%', ?1, '%') might be the solution

Use PDO's bind param multiple times as variable

I was searching over the internet and i didnt find any solution.
Lets say i want to use one paramerer in PDO multiple times.
SELECT *
FROM `users`
INNER JOIN `user_names` ON `users`.`id`=`user_names`.`id`
WHERE `user_names`.`name` LIKE CONCAT('%', ? ,'%') OR `users`.`name` LIKE CONCAT('%', ? ,'%')
How can i avoid to use ? two times ? I am looking for something like this:
SELECT ? AS `search_name`, *
FROM `users`
INNER JOIN `user_names` ON `users`.`id`=`user_names`.`id`
WHERE `user_names`.`name` LIKE CONCAT('%', `search_name` ,'%') OR `users`.`name` LIKE CONCAT('%', `search_name` ,'%')
Thank you
You can join an extra subselect that contains the parameter value or (like I do below) the complete search string.
SELECT *
FROM `users`
INNER JOIN `user_names` ON `users`.`id`=`user_names`.`id`
CROSS JOIN (SELECT CONCAT('%', x.name, '%') as SearchString) x
WHERE `user_names`.`name` LIKE x.SearchString OR `users`.`name` LIKE x.SearchString
You cannot do this in the normal mode. The only way to get around this is to use named parameters with emulation mode turned on (PDO::ATTR_EMULATE_PREPARES).
I, however, typically advise against doing this though and just recommend using multiple bindParam statements using named parameters instead of question marks. So you can use :searchname1 and :searchname2 both connected with the same POST/GET variable.

MySQL error code 1064 syntax error

This is a very specific question to the kind of code i have written for postgresql and i am migrating to mysql for project requirements.
The code written so far in mysql is as follows :
(select substring(dt,1,9) as dt,concat(vish,visl,visn) as vis,ip
from assignment_walmart.b
where service='ss' and ua not like '%ktxn%'
and ua not like '%khte%'
and ua not like '%keynote%'
group by 1,2,3
) as A1
left join // This is where it shows the error.
(select ip,flag from
assignment_walmart.b1
group by 1,2
) as A2
on A1.ip=A2.ip
where A2.flag is NULL
group by 1,2;
The error is popping up near the naming of the two selected tables as "A1" and "A2", so i'm assuming it's not allowed in mysql.
Can you please help me with an alternate syntax for the above code as I have to use the two tables in this manner only to join in to get required results.
How exactly do i use alias or join 2 tables in such a manner which was clearly working in postgresql?
Any help would be appreciated.
You have a subquery joined to another query. This shouldn't work in either database. You need to wrap these in a select or something like that:
select A2.dt, A2.vis, count(*)
from (select substring(dt,1,9) as dt, concat(vish,visl,visn) as vis,ip
from assignment_walmart.b
where service='ss' and ua not like '%ktxn%'
and ua not like '%khte%'
and ua not like '%keynote%'
group by substring(dt,1,9), concat(vish,visl,visn), ip
) as A1 left join // This is where it shows the error.
(select ip,flag from
assignment_walmart.b1
group by ip, flag
) as A2
on A1.ip=A2.ip
where A2.flag is NULL
group by A2.dt, A2.vis;
I am making a guess on what you want for the outer query and what the aggregation fields are. It is a good idea to be explicit about which fields are being aggregated.
It looks like you are missing the SELECT ... FROM on the outer query.
It looks you mean for your query to be of the form:
SELECT ...
FROM ( inline view query ) A1
LEFT
JOIN ( inline view query ) A2
ON A1.col = A2.col ...
WHERE ...
GROUP BY ...

Query is Giving Wrong Results

SELECT `bio_community_groups`.`id`, `bio_community_groups`.`name`, `bio_community_groups`.`description`, `bio_community_groups`.`members`
FROM `bio_community_groups`
WHERE `bio_community_groups`.`category_id` = '1'
AND `bio_community_groups`.`name` LIKE '%rock%'
OR `bio_community_groups`.`description` LIKE '%rock%'
Problem: there isn't group with ID = 1, but anyway... it gives me all groups where name or description is like '%rock%'.
Maybe brackets may help me? Where should I put them?
Perhaps this is what you might be looking for :
SELECT `bio_community_groups`.`id`, `bio_community_groups`.`name`, `bio_community_groups`.`description`, `bio_community_groups`.`members`
FROM `bio_community_groups`
WHERE
( `bio_community_groups`.`category_id` = '1' )
AND
( `bio_community_groups`.`name` LIKE '%rock%'
OR `bio_community_groups`.`description` LIKE '%rock%' );
In your original query, you will get results satisfying :
`bio_community_groups`.`description` LIKE '%rock%
whatever the category_id may be .
AND precedes OR in MySQL. so your query is like (bio_community_groups.category_id = '1'
AND bio_community_groups.name LIKE '%rock%')
OR (bio_community_groups.description LIKE '%rock%). Just place the appropriate brackets to resolve this

Tricky SQL including outer join and case

I use data from http://geonames.org. The table structure is as follows:
GN_Name 1 - 0:N GN_AlternateName
They are linked on:
(PK)GN_Name.GeoNameId == (FK)GN_AlternateName.GeoNameId
GN_Name is the main table containing all place names.
GN_AlternateName contains names in other languages if any.
EX:
GN_Name.Name - Stockholm
GN_AlternateName.AlternateName - Estocolmo (if IsoLanguage=="es")
Rules:
I want to use GN_AlternateName.AlternateName if it exists for the specified language and if it starts with the search string.
If not, i want to use GN_Name.Name if it starts with the search string.
I want GeoNameId to be unique.
Basically I could outer join in first record only, but that seemed to decrease performance.
I've got the following SQL (basically modified SQL from a LINQ query). The problem is that it only finds 'Estocolmo' if search string starts with "stock". "estoc" yields nothing.
select
distinct(n.GeoNameId) as Id,
an.IsoLanguage,
CASE WHEN (an.AlternateName like N'estoc%')
THEN an.AlternateName
ELSE n.Name
END AS [The name we are going to use]
from GN_Name as n
LEFT OUTER JOIN GN_AlternateName as an
ON n.GeoNameId = an.GeoNameId
AND 'es' = an.IsoLanguage
WHERE n.Name like N'estoc%'
UPDATE
Thanks Rahul and Lee D.
I now have the following:
select
distinct(n.GeoNameId) as Id,
an.IsoLanguage,
CASE WHEN (an.AlternateName like N'estoc%')
THEN an.AlternateName
ELSE n.Name
END AS [The final name]
from GN_Name as n
LEFT OUTER JOIN GN_AlternateName as an
ON n.GeoNameId = an.GeoNameId
AND 'es' = an.IsoLanguage
WHERE (n.Name LIKE N'estoc%' OR an.AlternateName LIKE N'estoc%')
This performs LIKE twice on an.AlternateName. Is there any way i could get rid of on LIKE clause?
UPDATE 2
Andriy M made a nice alternative query using COALESCE. I changed it a little bit and ended up with the following:
SELECT Id, LocalisedName
FROM (
SELECT
n.GeoNameId AS Id,
an.IsoLanguage,
COALESCE(an.AlternateName, n.Name) AS LocalisedName
FROM n
LEFT JOIN GN_AlternateName AS an ON n.GeoNameId = an.GeoNameId
AND IsoLanguage = 'es'
) x
WHERE LocalisedName LIKE 'estoc%'
This query does exactly what i am looking for. Thanks!
Here's a probable solution of the problem, which uses a slightly different apporach:
SELECT Id, LocalisedName
FROM (
SELECT
n.GeoNameId AS Id,
an.IsoLanguage,
COALESCE(an.AlternateName, n.Name) AS LocalisedName
FROM GN_Name AS n
LEFT JOIN GN_AlternateName AS an ON n.GeoNameId = an.GeoNameId
AND IsoLanguage = 'es'
) x
WHERE LocalisedName LIKE 'estoc%'
(Changed it based on your update.)
If I understand correctly, in your example the value 'Estocolmo' is in the GN_AlternateName.AlternateName column, so would be filtered out by the where clause which only looks at GN_Name.Name. What if you change the last line of SQL to:
WHERE n.Name LIKE N'estoc%' OR an.AlternateName LIKE N'estoc%'
I'm assuming 'estoc%' is your search string.
I guess you need to modify the WHERE clause to check in GN_AlternateName table as well
WHERE n.Name like N'estoc%' OR an.AlternateName like 'N'estoc%'