locate mysql function doesnt play nice with unicodes? - mysql

i have the following query
SELECT *
FROM `keywords`
WHERE name LIKE '%ba%'
ORDER BY LOCATE( 'ba', name ) , name
LIMIT 0 , 30
this query should sort result by the appreance of 'ba' in side keywords.name. but, I'm getting some weird behavior on some special chars:if - for example - i have the word Ghurabā the query
like %ba% will find it. but, it seems that locate(Ghurabā,ba) will return 0 - meaning as pattern was not found in string
any idea how to overcome this issue?
p.s -some useful data:
the result of the query above :
Ghurabā'
Khuṭabā'
qabā\
Ribāṭ
ba'urchi (cook)
Baghdad
...
note that it does work for "regular english characters" but there is a mismatch between the like and the locate function
Using Collcation: utf8_general_ci (got the same result with utf_unicode_ci)
mysql:effected version mysql 5.5/5.6 ( and probably lower)
EDIT:
expected result of the query above should be something like
'
Baghdad
ba'urchi (cook)
qabā\
Ribāṭ
Ghurabā'
Khuṭabā'
note : order by the distance of ab from the beginning of the word and then order by name
...

You should use BINARY operator to compare strings. Check these query -
SELECT
name,
name LIKE BINARY '%ba%',
name LIKE '%ba%',
LOCATE('ba', name)
FROM
`keywords`;
From the documentation:
LOCATE- this function is multi-byte safe
LIKE - performs matching on a per-character basis

Related

MySQL SUBSTR LOCATE multi-search-strings

Tricky one, and my brain is mush after staring at my screen for about an hour.
I'm trying to query my database to return the first part of a string (domain name eg. http://www.example.com) in the column image_link.
I have managed this for all rows where the image_link contains .com as part of the string... but I need the code to be more versatile, so it searches for the likes of .net and .co.uk too.
Had thought some sort of nested REPLACE might work, but it doesn't make sense when I try to apply it - and I'm stuck.
Query Builder code:
$builder->select("SUBSTRING(image_link, 1, LOCATE('.com', image_link) + 3) AS domain");
Example strings, with desired results:
http://www.example.com/brands/567.jpg // http://www.example.com
https://www.example.org/photo.png // https://www.example.org
http://example.net/789 // http://example.net
Any help/advice warmly welcomed!
SELECT ... ,
SUBSTRING_INDEX(image_link, '/', 3) domain
FROM test;
Or, if protocol may be absent, then
SELECT ... ,
SUBSTRING_INDEX(image_link, '/', CASE WHEN LOCATE('//', image_link) THEN 3 ELSE 1 END) domain
FROM test;
fiddle

Mysql Query Request

Straight to the point and this might be very simple for some of you.
I have a simple SELECT query (select description from table) which produces all i want like below :
- testword123
- testword875
- myjob1 45
- myjob is 544
What i need is to have as a result :
- testword
- myjob
I can use a SELECT distinct LEFT(description,8) which works fine, but the problem is not ALL 'description' have the same number of words :-(
So basically, what i want is retrieve ONLY the letters from the 'description' result set.
Thanks!!
R
SELECT distinct LEFT(description, charindex(' ', description) - 1)
Depending on your implementation, it might be possible to declare 'description' as a variable beforehand so you don't have to type it twice in the same query.
There are two decisions:
1) Handle each decription in PHP
or
2) Handle user input before writing it to DB. Add field to table as index of first not letter symbol and then use it in LEFT mysql function
Thanks "undefined_variable" - Your solution "stackoverflow.com/questions/11134452/…; was the correct one!! (y) (with a little bit of tweaking, this helped A LOT) A+++

Django raw SQL query trouble with format characters and string interpolation

In my Django app, I need to generate a MySQL query like this:
SELECT * FROM player WHERE (myapp_player.sport_id = 4 AND (myapp_player.last_name LIKE 'smi%'))
UNION
SELECT * FROM player WHERE (myapp_player.sport_id = 4 AND (myapp_player.first_name LIKE 'smi%'));
I can't use Q objects to OR together the __istartswith filters because the query generated by the Django ORM does not use UNION and it runs at least 40 times slower than the UNION query above. For my application, this performance is unacceptable.
So I'm trying stuff like this:
Player.objects.raw("SELECT * FROM myapp_player WHERE (sport_id = %%s AND (last_name LIKE '%%s%')) UNION SELECT * FROM sports_player WHERE (sport_id = %%s AND (first_name LIKE '%%s%'))", (sport.id, qword, sport.id, qword))
I apologize for the long one-liner, but I wanted to avoid using a triple-quoted string while trying to debug this type of issue.
When I execute or repr this queryset object, I get exceptions like this:
*** ValueError: unsupported format character ''' (0x27) at index 133
That's a single-quote in single quotes, not a triple-quote. If I get rid of the single-quotes around the LIKE clauses, then I get a similar exception about the close-paren ) character that follows the LIKE clause.
Apparently Django and MySQL disagree on the correct syntax for this query, but is there a syntax that will work for both?
Finally, I'm not sure that my %%s syntax for string interpolation is correct, either. The Django docs suggest that I should be able to use the regular %s syntax in the arguments for raw(), but several online resources suggest using %%s or ? as the placeholder for string interpolation in raw SQL.
My sincere thanks for just a little bit of clarity on this issue!
I got it to work like this:
qword = word + '%'
Player.objects.raw("SELECT * FROM myapp_player WHERE (sport_id = %s AND (last_name LIKE %s)) UNION SELECT * FROM myapp_player WHERE (sport_id = %s AND (first_name LIKE %s))", (sport.id, qword, sport.id, qword))
Besides the fact that %s seems to be the correct way to parameterize the raw query, the key here was to add the % wildcard to the LIKE clause before calling raw() and to exclude the single quotes from around the LIKE clause. Even though there are no quotes around the LIKE clause, quotes appear in the query ultimately sent to the MySQL sever.

Select query returns false result

eg:
Table : user
column : user_id (type is int)
SELECT * FROM user WHERE user_id = '10xyz'
is giving same result of
SELECT * FROM user WHERE user_id = '10'
The input value is not integer but not giving an error in this case.
The reason why you are getting the same result is because MySQL automatically removes the trailing characters from the string and implicitly converts it to integer.
SQLFiddle Demo
SQLFiddle Demo (updated)
If you don't want to change all your code, but you have your database queries all going through one or a few subs, you can change those to check for warnings after using a statement handle (e.g. if ( $sth->{mysql_warning_count} ) ...).
Or you can create a DBI subclass that does that automatically for you, promoting warnings to errors. If you do, many others have use for such a thing. There are configuration settings to give an error instead of a warning when updating or inserting something like '10xyz' into an integer field, but not anything broader than that, and dear Oracle considers it Not a Bug. Maybe MariaDB does (or could do) better?
datatype of user_id is in database is INT
that why it giving same output and not error

ORDERBY "human" alphabetical order using SQL string manipulation

I have a table of posts with titles that are in "human" alphabetical order but not in computer alphabetical order. These are in two flavors, numerical and alphabetical:
Numerical: Figure 1.9, Figure 1.10, Figure 1.11...
Alphabetical: Figure 1A ... Figure 1Z ... Figure 1AA
If I orderby title, the result is that 1.10-1.19 come between 1.1 and 1.2, and 1AA-1AZ come between 1A and 1B. But this is not what I want; I want "human" alphabetical order, in which 1.10 comes after 1.9 and 1AA comes after 1Z.
I am wondering if there's still a way in SQL to get the order that I want using string manipulation (or something else I haven't thought of).
I am not an expert in SQL, so I don't know if this is possible, but if there were a way to do conditional replacement, then it seems I could impose the order I want by doing this:
delete the period (which can be done with replace, right?)
if the remaining figure number is more than three characters, add a 0 (zero) after the first character.
This would seem to give me the outcome I want: 1.9 would become 109, which comes before 110; 1Z would become 10Z, which comes before 1AA. But can it be done in SQL? If so, what would the syntax be?
Note that I don't want to modify the data itself—just to output the results of the query in the order described.
This is in the context of a Wordpress installation, but I think the question is more suitably an SQL question because various things (such as pagination) depend on the ordering happening at the MySQL query stage, rather than in PHP.
My first thought is to add an additional column that is updated by a trigger or other outside mechanism.
1) Use that column to do the order by
2) Whatever mechanism updates the column will have the logic to create an acceptable order by surrogate (e.g. it would turn 1.1 into AAA or something like that).
Regardless...this is going to be a pain. I do not evny you.
You can create function which have logic to have human sort order like
Alter FUNCTION [dbo].[GetHumanSortOrder] (#ColumnName VARCHAR(50))
RETURNS VARCHAR(20)
AS
BEGIN
DECLARE #HumanSortOrder VARCHAR(20)
SELECT #HumanSortOrder =
CASE
WHEN (LEN(replace(replace(<Column_Name>,'.',''),'Figure ',''))) = 2
THEN
CONCAT (SUBSTRING(replace(replace(<Column_Name>,'.',''),'Figure ',''),1,1),'0',SUBSTRING(replace(replace(<Column_Name>,'.',''),'Figure ',''),2,2))
ELSE
replace(replace(<Column_Name>,'.',''),'Figure ','')
END
FROM <Table_Name> AS a (NOLOCK)
WHERE <Column_Name> = #ColumnName
RETURN #HumanSortOrder
END
this function give you like 104,107,119,10A, 10B etc as desired
And you can use this function as order by
SELECT * FROM <Table_Name> ORDER BY GetHumanSortOrder(<Column_Name>)
Hope this helps