Mysql match against numeric keyword - mysql

I use mysql full-text index.
I found it can not matches a key numeric word as '1' in '1,2,3' or '1 2 3'.
I use this query "SELECT * FROM users u where match(u.leader_uids) against('1' IN BOOLEAN MODE);"
How to solve this issue?
Thanks a lot!

I am Providing the example hope it will works for you i think
MATCH (field) AGAINST ('+856049' IN BOOLEAN MODE)

It will work only with words of 4 or more digits. So you must concat some prefix in the leader_uid before saving it. Example:
CREATE TABLE mytable(
id INT NOT NULL KEY AUTO_INCREMENT,
myfield TEXT,
FULLTEXT KEY ix_mytable (myfield)
);
INSERT INTO mytable (myfield) VALUES
('id_1 id_2 id_3'),
('id_8'),
('id_4 id_1');
SELECT * FROM mytable
WHERE MATCH(myfield) AGAINST ('+id_1' IN BOOLEAN MODE);
-- will select rows 1 and 3
You can change the minimum amount of chars required for the words, in mysql config:
https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_ft_min_token_size

Related

MySQL full text search - no partial recognition

I'm trying to build a keyword search tool based on mysql and I can only get results for full words while I would like to get results for partial matches too.
My db structure looks like this:
My db content looks like this:
This query works:
select * from chromext_keyword where matches (keyword) against ('Redmi')
But this one doesn't work (no result):
select * from chromext_keyword where matches (keyword) against ('red')
I tried with % but it did not solve the problem. I tried the natural language option as well as boolean but it didn't help.
Update with create table query:
CREATE TABLE chromext_keywords (
id int(10) NOT NULL,
keyword text NOT NULL,
blacklist text NOT NULL,
category text NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
and insert:
INSERT INTO chromext_keywords (id, keyword, blacklist, category) VALUES
(1, 'Redmi Note 10', '9,8,pro', '2'),
(2, 'Realme GT', '6,7,8,narzo', '2');
and I added full text:
ALTER TABLE chromext_keywords
ADD UNIQUE KEY id (id);
ALTER TABLE chromext_keywords ADD FULLTEXT KEY keyword (keyword);
I have also tried innoDb and Myisam
Am I missing something?
Thanks
You should check for Minimum word lenght setting ..
in mysql the minimum length for full text search in limited by the param
ft_min_word_len
and the defualt value is for words > 3
take a look at the related docs
https://dev.mysql.com/doc/refman/8.0/en/fulltext-fine-tuning.html
I have finally found the answer.
The following query works:
SELECT * FROM chromext_keywords WHERE match(keyword) against('(re*)') IN BOOLEAN MODE)
With multiple keywords:
SELECT * FROM chromext_keywords WHERE match (keyword) against ('(+red*+not*)') IN BOOLEAN MODE)
I still need to figure out how to cover spelling mistakes. If anyone has an idea, let me know.

MySQL SELECT row based on prefix

Im attempting to do a SELECT on data in a table that contains prefixes, and I have the "keyword".
So unlike a normal search where the prefix/keyword is contained in the row data, and that the prefix/keyword is shorter (or contained in) a possible row of data.
This is the opposite. If have prefixes in rows and I want to find the best matching row based on the (longer) word/phase.
CREATE TABLE table1 (id INT NOT NULL AUTO_INCREMENT, keyCode VARCHAR(45) NULL, Username VARCHAR(45) NULL, PRIMARY KEY (id));
INSERT INTO table1(keyCode,Username)VALUES('123','Peter')
INSERT INTO table1(keyCode,Username)VALUES('456','Paul')
INSERT INTO table1(keyCode,Username)VALUES('1234','John')
Now let's say the phrase I have been given is longer than the prefix in the data.
Like this:
SELECT * FROM table1 WHERE keyCode LIKE '123456%';
I know this will not work, but I would like to return the Row with User 'John'.
How?
(I can use stored procedures)
You may phrase your LIKE expression in the reverse order:
SELECT *
FROM table1
WHERE '123456' LIKE CONCAT(keyCode, '%');
This would compare, for example, '123456' against '1234%', which should be a match in this case.
You can check for the existence of the keyCode prefix at the beginning of your string using LOCATE(). For example:
SELECT *
FROM table1
WHERE LOCATE(keyCode,'123456') = 1;

Why MySQL "WHERE" clause approximation: retrieves values even the condition is not met

I have a table which primary key is numeric and auto-incremented.
When I run a query such as:
SELECT * FROM my_table where id = '1a';
The query returns the row with the primary key set to "1".
I was not aware of this behavior, is it possible to prevent it?
I was expecting this WHERE clause to retrieve nothing since the id is "1" and not "1a". It is behaving like it was a LIKE clause.
MySQL implicitly converts a String literal to int while comparing with an int column.
You should really fix your application code (eg: PHP), and properly typecast to (int) before using them in a query. Ideally, your application should not have been inputting string values to compare against an integer field.
Now still, if you don't have control over input value, an approach can be to check if the value is numeric or not, and use it accordingly for comparison. Adapting a sargable approach from https://dba.stackexchange.com/q/89760/160363
SELECT * FROM my_table
WHERE id = CASE WHEN CONCAT('','1a'*1) = '1a' THEN '1a' ELSE NULL END;
mysql automatically converts strings to numbers, and just takes the leading characters that are digits. You could instead explicitly cast the ID to a string:
SELECT * FROM my_table where CAST(id AS CHAR) = '1a';

find_in_set return different value

I have a table with this declaration:
CREATE TABLE foobar (
id int(11) NOT NULL AUTO_INCREMENT,
dow set('q','w','e','r','t','y', 'u') NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT;
With those values inside:
id, dow
'1', '1,3,6'
'1', '2,4,7'
Those query returns different values.
SELECT dow, FIND_IN_SET('4', dow) FROM (SELECT * from pippo.pluto) as B;
SELECT dow, FIND_IN_SET('4', dow) FROM pippo.pluto as B;
The first query returns those results:
'1,3,6', '0'
'2,4,7', '2'
The second query returns those results:
'1,3,6', '0'
'2,4,7', '4'
Why?
Tested against 5.6 and 5.7 mysql version.
Edit:
This behaviour remains the same if I use the mysql views.
CREATE VIEW selectInner AS SELECT dow, FIND_IN_SET('r', dow) FROM (SELECT * from pippo.foobar) as B;
CREATE VIEW selectDirect AS SELECT dow, FIND_IN_SET('r', dow) FROM pippo.foobar as B;
There are two things interacting here:
"If the first argument is a constant string and the second is a column of type SET, the FIND_IN_SET() function is optimized to use bit arithmetic." per FIND_IN_SET docs
One of the two queries operates directly on the table, and the second on a derived table.
The behaviour demonstrates this:
When operating directly on the table (where dow refers to the defined column in that table's metadata), FIND_IN_SET returns the index of the entry in the column's definition
When operating on a derived table (where dow refers to a derived column), FIND_IN_SET returns the index of the entry in the derived value
This is clear if you search for e.g. y and u in a column containing q,e,y,u: you'd get 6 and 7 when querying the table directly, where dow is a SET containing q,w,e,r,t,y,u and FIND_IN_SET uses bitwise optimizations; but 3 and 4 when searching the derived table, where dow is the string containing q,e,y,u for that row.

MySQL Order By doesn't work on Concat(enum)

Currently we have an interessting problem regarding the sort order of MySQL in an enum-field. The fields enum entries have been sorted in the order we want it. Just to be save, we added a CONCAT around it, so it would be cast to char and ordered in alphabetical order, just as suggested by the MySQL-reference (MySQL Reference - Enum)
Make sure that the column is sorted lexically rather than by index number by coding ORDER BY CAST(col AS CHAR) or ORDER BY CONCAT(col).
But that didn't produce the expected results, so we started to investigate further. It seems that the order by statement doesn't work on a combination of enum and the concat function. I've wrote the following sample script, which should show my point:
CREATE TABLE test (
`col1` enum('a','b','c') COLLATE utf8_bin DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
INSERT INTO test
VALUES ('b'), ('c'), ('a');
SELECT * FROM test; -- b, c, a
SELECT * FROM test ORDER BY col1 ASC; -- a, b, c
SELECT * FROM test ORDER BY CAST(col1 AS CHAR) ASC; -- a, b, c
SELECT * FROM test ORDER BY CAST(col1 AS BINARY) ASC; -- a, b, c
SELECT * FROM test ORDER BY CONCAT(col1) ASC; -- b, c, a - This goes wrong
I am currently suspecting some kind of problem with the collation/encoding, but I'm not sure. My databases default encoding is also utf8. The MySQL version is 5.6.12 but it seems to be reproduceable with MySQL 5.1. The storage engine is MyIsam but it also occurs with the memory engine.
Any help would be appreciated.
Update:
As it seems the problem is produced only in MySQL 5.6 and by the collation of the column. With the first CREATE TABLE statement, the queries work fine.
CREATE TABLE test (
`col1` enum('a','b','c') COLLATE utf8_general_ci DEFAULT NULL
)
With the second they don't.
CREATE TABLE test (
`col1` enum('a','b','c') COLLATE utf8_bin DEFAULT NULL
)
The collation of the table and/or database don't seem to affect the queries. The queries can be tested in this SQL Fiddle
Strange,it works in this fiddle.Do you have a trigger or something?
http://sqlfiddle.com/#!2/0976a/2
BUT,in 5.6 goes haywire:
http://sqlfiddle.com/#!9/0976a/1
Mysql bug,probably.
More,if you input the values in the enum in the "proper" order it works:
http://sqlfiddle.com/#!9/a3784/1
IN the doc:
ENUM values are sorted based on their index numbers, which depend on
the order in which the enumeration members were listed in the column
specification. For example, 'b' sorts before 'a' for ENUM('b', 'a').
As per the document:
Under the Handling of Enumeration Literals section, it states that:
If you store a number into an ENUM column, the number is treated as
the index into the possible values, and the value stored is the
enumeration member with that index. (However, this does not work with
LOAD DATA, which treats all input as strings.) If the numeric value is
quoted, it is still interpreted as an index if there is no matching
string in the list of enumeration values. For these reasons, it is not
advisable to define an ENUM column with enumeration values that look
like numbers, because this can easily become confusing.
For example, the following column has enumeration members with string values of '0', '1', and '2', but numeric index values of 1, 2, and 3:
numbers ENUM('0','1','2')
If you store 2, it is interpreted as an
index value, and becomes '1' (the value with index 2). If you store
'2', it matches an enumeration value, so it is stored as '2'. If you
store '3', it does not match any enumeration value, so it is treated
as an index and becomes '2' (the value with index 3).
mysql> INSERT INTO t (numbers) VALUES(2),('2'),('3');
mysql> SELECT * FROM t;
+---------+
| numbers |
+---------+
| 1 |
| 2 |
| 2 |
+---------+
In your case:
INSERT INTO test
VALUES ('2'), ('3'), ('1');
Index value of '2' is 2, '3' is 3 and '1' is 1.
So the output is 2,3,1