Reverse IN function - mysql

Consider the following table teammessages:
15:10 | Peter | I'm off to the store, call my mobile phone if you need me.
15:11 | Susy | Have you seen the new scanner? It's lightning fast.
15:15 | Anne | We have an emergency here, John broke the tap! Please switch off the water supply!
15:15 | John | I did what?? :-D I'm in Vienna!
15:16 | Peter | I'm stuck in the elevator, help!
15:17 | Anne | I said WATER, not POWER supply!
When I want to SELECT the urgent messages, containing key words like "help" or "emergency", from that chaotic freetext, I would have to have a "reverse IN" function, which doesn't check if the field is IN a given list of alternatives (WHERE APPLECOLOR IN ('YELLOW', 'RED')) but which checks if a value of the given alternatives is IN the field (WHERE freetext REVERSE_IN ('help', 'emergency')).
I've tried constructs like WHERE freetext LIKE ('%help%' OR '%emergency%'), but this gives me empty results.
Clarification: I can do this with freetext LIKE ... OR freetext LIKE ... OR freetext LIKE ... but it gets very long. So I am just looking for a shorthand like IN is in the "reverse case" (APPLECOLOR = 'RED' OR APPLECOLOR = 'YELLOW' <=> APPLECOLOR IN ('RED', 'YELLOW')).

The correct form of your original query is:
WHERE freetext LIKE '%help%' OR freetext LIKE '%emergency%'
However you might also like to consider using MATCH. For that you will need to have a FULLTEXT index on the message column which you can add with this command:
ALTER TABLE teammessages ADD FULLTEXT INDEX(message);
You can then search using a query like this one:
SELECT *
FROM teammessages
WHERE MATCH(message) AGAINST('help emergency' IN BOOLEAN MODE)
which will give you better results than LIKE, which would also match words like 'whelp' or 'helpful' or 'helps'. In your sample table, this query returns:
time name message
15:15:00 Anne We have an emergency here, John broke the tap! Please switch off the water supply!
15:16:00 Peter I'm stuck in the elevator, help!
This query also has the advantage of not getting long as fast as multiple LIKEs

I suggest a Generated Column.
Answers involving LIKE are going to be very slow here, and answers involving full text search (freetext) expressions are telling MySql to index every word in the column, rather than just the words you care about.
You can use a generated column to produce a simple Y/N or 1/0 result for just the words you care about that only needs to evaluate the full column data at INSERT/UPDATE time.

You are probably looking for the words help and emergency. You don't want to find
Jake, your jokes are not helpful.
You must subtract the tax. Hope this helps :-)
So check whether your version of MySQL supports regular expressions where you can look for words:
select *
from teammessages
where freetext regexp '[[:<:]](help|emergency)[[:>:]]';
Rextester demo: http://rextester.com/ILROPQ12660

WHERE freetext LIKE ('%help%' OR '%emergency%') does not work like this.
It should be:
WHERE freetext LIKE '%help%' OR freetext LIKE '%emergency%'
Additional: From documentation of LIKE function:
With LIKE you can use the following two wildcard characters in the
pattern:
% matches any number of characters, even zero characters.
_ matches exactly one character.
mysql> SELECT 'David!' LIKE 'David_';
-> 1
mysql> SELECT 'David!' LIKE '%D%v%';
-> 1

you should try :
WHERE freetext LIKE('%help%') OR freetext LIKE('%emergency%')

You could find all messages that are urgent with keywords you know by doing something similar to this:
SELECT * FROM teammessages WHERE freetext LIKE '%help%' OR freetext LIKE '%emergency%';
You could do the 'reverse' of this by using NOT LIKE this way:
SELECT * FROM teammessages WHERE freetext NOT LIKE '%help%' AND freetext NOT LIKE '%emergency%';

Related

MySQL fulltext search results fine tune

I have an InnoDB table with 5000 rows. Here is an example of my table named 'insitutes'.
id| name
1 | University of London
2 | Department of Maths University of London
3 | Department of Biology University of London
4 | Department of Chemistry University of London
5 | Department of Physics University of London
...
This is what my query looks like
SELECT *,
MATCH (name) AGAINST ('London University' IN BOOLEAN MODE) AS score
FROM insitutes
WHERE MATCH (name) AGAINST ('London University' IN BOOLEAN MODE)
ORDER BY score DESC
This is what my result will look like
Department of Biology University of London
Department of Maths University of London
Department of Chemistry University of London
University of London
....
I want to get 'University of London' as the first result. Saying this I mean I want to get the closest match to the search query.
By playing with my data I found out that changing the table type to MyISAM and modifying the query to 'IN NATURAL LANGUAGE MODE' will give me expected results. But I cannot use the table type MyISAM as it does not indexes words less than 4 charaters.
First of all, you can indeed control the minimum word size in your MyISAM fulltext index, with ft_min_word_len.
SET ft_min_word_len= 3
or whatever you need, will do it. You probably want to make sure it's set in your MySQL my.cnf file too, so if your server restarts it's still set.
Second, the word of in your search term is in the FULLTEXT stoplist. You can't use it for matching unless you remove it from the stoplist.
And, if you have managed to include of in your index, notice that the department name strings contain it twice, which will boost their score.
If you change FULLTEXT's configuration be sure to rebuild your index.
Third, as you know the order of your resultset comes from the score assigned to each row by FULLTEXT. FULLTEXT is designed as an assistance to human perception. It presents choices for a human to choose among, rather than precisely correct choices. Expecting perfectly predictable results from FULLTEXT is probably a mistake.
What ever letter We Can Use As Text. If U Have Problem Say Me More Clearly. Ok ?
I Think You Can Use Mysql Query Like This:
select
*, count(name)
from
insitutes
where
name like "%London University%"
order by
name desc;
Once Check This If This Statement Works Say Me Else Define Your Problem More Clearly.

MySql: turn decimal to percent upon viewing the table

I saw a post here in stack overflow with question and answer very similar to my problem.
its this post:
MySQL: turn decimal into percent within view
and as said in the post above, use:
CONCAT(columnname * 100, '%')
and thats what i actually did..
i have a table with a column for percentages for specific ranges of salary.
its a salary deduction schedule.
i stored the percent values as a decimal datatype in column "ee".
ee | decimal(4,4) | not null
and my problem is its giving me this result and its not what i wanted..
for example, an entry in the column is 0.0200, and i want to show it upon viewing as "2%", but this is what i get.
select s_b,rangeA,rangeB,concat(ee * 100,'%') as 'ee_percent' from htbl;
+___________________________________+
|s_b| rangeA| rangeB|ee_percent |
+---+--------+---------+------------+
| 1| 0.00| 1500.00| 1.0000% |
| 2| 1500.00|999999.99| 2.0000% |
+-----------------------------------+
I know that this is a duplicate and an elementary question, but i don't know why its not working,
if you see a mistake somewhere in my syntax, or in the data type please tell me.
any suggestions and corrections are highly appreciated. Thank you so much.
You can use the following solution using FORMAT:
SELECT s_b, rangeA, rangeB, CONCAT(FORMAT(ee * 100, 0), '%') AS 'ee_percent'
FROM htbl;
The result of the calculation is always DECIMAL(4,4). So MySQL show the result with four decimal places. You can use the FORMAT function to format the result or other functions which remove the decimal places.
demo: https://www.db-fiddle.com/f/ncjBpJRwdQVbT7PUBoXgeU/0
You can try with Floor function,
select s_b,rangeA,rangeB,concat(FLOOR(ee * 100),'%') as 'ee_percent' from htbl;
Use round, i.e:
select s_b,rangeA,rangeB,concat(round(ee * 100),'%') as 'ee_percent' from htbl;

How to check if any member of a needle array is in a haystack string via MySQL query

If I have a column of possible choices:
choices
-------
Coke
Pepsi
7-Up
Water
And I have a table of user feedback, how could I check to see if the feedback contains the list of choices? Or more specific to my issue, I'm checking to see if the feedback contains the phrase: "I love {one of the choices}". The list of choices can grow over time, but the feedback may have phrases such as "I love Milk" which I don't want to show up in the results. Similarly, the feedback may say "I hate Water", which should not be in the results (unless, of course, they also say "I love Water" in the feedback). So just doing a keyword match wouldn't work.
Is there is a function similar to INSTR and IN, where I could say, maybe:
SELECT feedback_id FROM feedback where
INSET(feedback_note, SELECT CONCAT("I Love ", choices) FROM choice_list)
Update
I didn't know about the ANY operator worked until after asking, but my attempt to use it isn't working. I tried:
SELECT feedback_id, feedback_note FROM feedback
having feedback_note LIKE ANY
(SELECT distinct CONCAT("I love ", choices, "%") from choice_list);
This is just not allowed, I learned, so I thought I'd at least see if would work for a one line "I love Pepsi" so I did:
SELECT feedback_id, feedback_note FROM feedback
having feedback_note = ANY
(SELECT distinct CONCAT("I love ", choices, "%") from choice_list);
And after a minute or so, the query was still running (I executed it). So is there some way to use LIKE and ANY together, maybe not directly?
You could use the LIKE condition with wildcards.
For, example if you have the following table schema:
[choices]
id | text
1 | Coke
2 | Pepsi
[feedback]
id | note
1 | I love Pepsi.
2 | I really like Coke
3 | This comment has nothing to do with anything
In PostgreSQL you could do something like:
SELECT feedback.id
FROM feedback, choices
WHERE choices.text in (SELECT text FROM choices)
AND feedback.note LIKE '%' || text || '%'
or
SELECT feedback.id
FROM feedback
INNER JOIN choices ON feedback.note LIKE '%' || choices.text || '%'
(the second one is faster)
% is the wildcard operator, the LIKE condition will match anything that has choice between any other characters.
I have no way to test this code right now, but something similar should work in PostgreSQL.
ps: || is the string concatenation operator in PostgreSQL, beware that string concatenation varies between rdbms.
ps2: you can also use ILIKE instead of LIKE if you want it to be case insensitive
My approach:
SELECT feedback_id, feedback_note
FROM feedback
WHERE
SUBSTRING(feedback_note,1,7) = "I Love " and
SUBSTRING(feedback_note FROM 8) in
(SELECT choices from choice_list)
or:
SELECT feedback_id, feedback_note
FROM feedback
WHERE
SUBSTRING(feedback_note,1,7) = "I Love " and
exists
(SELECT 1 from choice_list
where choices = SUBSTRING(feedback_note FROM 8)
)

Multiple LIKE in SQL

I wanted to search through multiple rows and obtain the row that contains a particular item.
The table in mySQL is setup so each id has a unique list (comma-delimited) of values per row.
Ex:
id | order
1 | 1,3,8,19,34,2,38
2 | 4,7,2,190,38
Now if I wanted to pull the row that contained just the number 19 how would I go about doing this? The possibilities I could figure in the list with a LIKE condition would be:
19, <-- 19 at the start of the list
,19 <-- 19 at the end of the list
,19, <-- 19 inside the list
I tried the following and I cannot obtain any results, Thank you for your help!
SELECT *
FROM categories
WHERE order LIKE '19,%' OR '%,19%' OR '%,19%'
LIMIT 0 , 30
First of all, you should not store values like this, you should use a child table with one row per item, this would make your current query that much easier to handle, and would allow for indexes to be used as well.
Having said that, what you want is this:
WHERE ',' + order + ',' LIKE '%,19,%'
By adding a comma in front of and after the list of values in the order field, you can query that field for the value you want with a comma on each side, and not have to deal with the special case of the value being the first or last value in the list.
With the query you listed, you could've made it work by realizing that OR doesn't give more arguments to the LIKE clause, it separates entirely different clauses, and thus rewritten the SQL like this:
WHERE order LIKE '19,%' OR order LIKE '%,19,%' OR order LIKE '%,19'
---+------ ^ ----+----- ^
| | | |
+- add this -+---------+ +- removed
percent
Note the missing comma in the second pattern there, which would match strings containing the value 19, and note the removed percentage character in the last ,which would allow it to match lists that ended with 19.
You can use FIND_IN_SET to solve your problem in a simpler way:
SELECT *
FROM categories
WHERE FIND_IN_SET('19', `order`)
LIMIT 0, 30
In general though you should try to design your database so that this type of operation is not necessary.

how to search a word from varchar(comma separated) field in mysql?

i have a table
table_movie
mid muid actor_name movie_list(varchar)
18 act_6 tom hanks mov_18,mov_19,mov_2,mov_22,mov_23
21 act_9 jhonny depp mov_1,mov_10,mov_20,mov_22,mov_3,mov_9
28 act_16 bruce willis mov_18,mov_19,mov_2,mov_22,mov_23
29 act_19 jhon trovolta mov_1,mov_10,mov_20,mov_22,mov_3,mov_9
now i want to dispplay only those actor_name and muid which have mov_1( which comes from php) in their movie_list
if i use EXIST then it show error, my query is written below
`SELECT muid,actor_name FROM table_movie WHERE $movieID EXIST( movie_list)`
i also tried with RLIKE but no results!:(
please tell me how to search a single word from a varchar field
NOTE
my table engine is INNODB so fultext search concept also fails
What about
SELECT muid,actor_name FROM table_movie WHERE movie_list LIKE '%,$movieID,%'
OR movie_list LIKE '%,$movieID'
OR movie_list LIKE '$movieID,%'
OR movie_list LIKE '$movieID'
?
Edit: I modified the query to take the comments into account. A bit ugly but I guess it would work. Forget about performance. Another problem would be titles with comma in it.
If you can modify the schem you could have a 'movie' table and a 'actor_movie' table.