Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
393 views
in Technique[技术] by (71.8m points)

MySQL: Querying for unicode entities

I need to find the word L?mm?nmyyntipalvelut from the database. Only, in the database it is in a field, whose value has been a PHP array, converted into JSON using json_encode() and so the special characters are scrabled into hex unicode.

So my query is

SELECT * FROM table WHERE (services LIKE '%L?mm?nmyyntipalvelut%')

No results. No surprise. Next, query with special characters converted:

SELECT * FROM table WHERE (services LIKE '%Lu00e4mmu00f6nmyyntipalvelut%')

No results and I wonder why. Next I tested querying for only special character:

SELECT * FROM table WHERE (services LIKE '%u00e4%')

Found what was supposed to find. Next I started adding stuff (L to beginning) to see where it went wrong:

SELECT * FROM table WHERE (services LIKE '%Lu00e4%')

No results. Another test:

SELECT * FROM table WHERE (services LIKE '%u00e4mm%')

Found what was supposed to find.

So my conclusion is that the backslash is somehow messing things up, but I don't understand how?

EDIT:

Exact contents of services field:

["Neuvonta","Lu00e4mmu00f6nmyyntipalvelut",
"Metsu00e4-/energiapuunkorjuupalvelut"]

Exact query:

SELECT id, uid, company_name, services, logo FROM rekisteroeidy_toimijaks 
WHERE 
    (services LIKE '%Lu00e4mmu00f6nmyyntipalvelut%' AND 
    services LIKE '%Metsu00e4-/energiapuunkorjuupalvelut%') 
ORDER BY company_name ASC

I added some line breaks to help readability.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I have absolutely no idea why, but triple escaping helps!

Well, that's only double-escaping, but yes it works and here's why: in MySQL, there is a second layer of escaping involved when you use the LIKE operator.

services LIKE '%L\\u00e4mm\\u00f6n%'

parsing that MySQL string literal gives you a comparison with the LIKE-query %L\u00e4mm\u00f6n%. Because MySQL treats in a LIKE query as an escape, that will actually match the literal string containing Lu00e4mmu00f6n.

The reason for this is so that you can match strings against a query expression that contains a literal % or _ character. For example if I want to search a column for the literal string 100%, I can match it against 100\% (written in a query as '100\%') and make sure I'm really getting one hundred percent and just not any string starting with a hundred.

It's unfortunate that MySQL uses backslash for both its LIKE query escaping and its string literal escaping, especially given that you're probably writing in an enclosing programming language that also uses them, ending up with actual triple-encoding, which looks like "services LIKE '%L\\\\u00e4mm\\\\u00f6n%'" - argh!

It's doubly unfortunate given that this behaviour is not ANSI SQL conformant, and won't work in any other database. ANSI SQL says that there is no escape character in LIKE queries by default, so if you want to match a literal % or _ you have to opt in by nominating an escape character of your own, eg.:

something LIKE '100=%' ESCAPE '='

For cross-database compatibility, it is best always to use the LIKE...ESCAPE form, and pick something other than the horrible backslash! (Aside - MySQL's backslashes for SQL string literal escaping aren't ANSI conformant either! But you can turn that misbehaviour off with the NO_BACKSLASH_ESCAPES sql_mode setting.)

Probably a better idea would be to break services out into a second table rather than squashing them into a single string column - ie. put your schema in First Normal Form. Then you could get a simple lookup of individual values rather than having to do a slow full-table-scan substring-match.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...