I have product tables in my database
Product table structure:
product_id | testid
------------------------------------
1 11,12,13
2 2,4
Below is my FIND_IN_SET query:
SELECT product_id FROM product
WHERE FIND_IN_SET(3, testid) > 0;
Output
0
Below is my LOCATE query:
SELECT product_id FROM product
WHERE LOCATE(3, testid) > 0;
output
1
My question
What is difference between FIND_IN_SET and LOCATE and what is the best way to find id in column
To put it in simple technical terms(PHP terminology), find_in_set is like substring function of PHP. It will accept a substring and a string as parameters, and return 1 if the substring is found within the string. It will return 0 if substring is not found.
On the contrary, LOCATE() returns the position of the first occurrence of a string within a string. It accepts, a substring and a string as parameters.
I think in your use case, find_in_set is the one you should go for. Because this is the one. find_in_set will return 1 if 3 is found in a row, where as locate will first occurance of 3 in the string even if it finds 31 or 300 as first element.
Difference between LOCATE() and FIND_IN_SET() Function
When using LOCATE() function for integers, suppose we need 1 to return from LOCATE() if integer 3 is in the set 1,2,3,4,5,.. the following MySQL commands can be written:
mysql> SELECT IF(LOCATE(3,'1,2,3,4,5,6,7,8,9')>0,1,0);
+-----------------------------------------+
| IF(LOCATE(3,'1,2,3,4,5,6,7,8,9')>0,1,0) |
+-----------------------------------------+
| 1 |
+-----------------------------------------+
1 row in set (0.06 sec)
The above command working rightly because the set contains the number 3 , but if we write the following commands, look what happened
mysql> SELECT IF(LOCATE(3,'11,12,13,14,15')>0,1,0);
+--------------------------------------+
| IF(LOCATE(3,'11,12,13,14,15')>0,1,0) |
+--------------------------------------+
| 1 |
+--------------------------------------+
1 row in set (0.02 sec)
Above the 3 is not present as a number three(3) in the given set, though the LOCATE() returns 1.
To avoid this type of situation you can use the FIND_IN_SET() function. Here is the example below:
mysql> SELECT IF(FIND_IN_SET(3,'11,12,13,4,5,6,7,8,9')>0,1,0);
+-------------------------------------------------+
| IF(FIND_IN_SET(3,'11,12,13,4,5,6,7,8,9')>0,1,0) |
+-------------------------------------------------+
| 0 |
+-------------------------------------------------+
1 row in set (0.05 sec)
So, LOCATE() function is very much suitable for string but not as much suitable for integer.
Examples, credits and some more information you can find here
So in your example FIND_IN_SET return 0 because there is no 3 in the given set, but LOCATE() returns 1 it treat the given set as a string but not a comma separated value, and the 3 present in the number 13
Related
mysql> select ordering, dst from alist where ordering=2 and dst like '%10.1.1.2%';
+----------+---------------------+
| ordering | dst |
+----------+---------------------+
| 2 | 10.1.1.1-10.1.1.254 |
+----------+---------------------+
1 row in set (0.00 sec)
If you want to match the literal path 10.1.1.2, and not things like 10.1.1.254, then you may try using REGEXP here:
SELECT ordering, dst
FROM alist
WHERE ordering = 2 AND dst REGEXP '[[:<:]]10.1.1.2[[:>:]]';
This corresponds to looking for the regex pattern \b10.1.1.2\b, i.e. there are word boundaries around your path.
The demo below correctly shows that there is no result set for your query as tested against the single row of sample data you provided.
Demo
I was trying to feed a result of a query as a parameter for another query and all was working fine except this field that has a datatype of bit. so i tried to convert the value of the field using convert() and cast() but it seems to be not working as its returning this wierd symbol of a small rectange which hava three 0's and a 1. so can anyone tell me why this is happening and how to fix it , here is my query
select CONVERT(isMale , char(5)) from person;
and the thing is it gives me the correct answer when i dont use the convert but since am giving this result to another query as a parameter it causing me the problem.
you can use BIN function like this:
SELECT BIN(isMale +0) from person;
sample
MariaDB [yourschema]> SELECT BIN(b'1001' +0) ;
+-----------------+
| BIN(b'1001' +0) |
+-----------------+
| 1001 |
+-----------------+
1 row in set (0.00 sec)
MariaDB [yourschema]>
Here some stuff from MariaDB Manual:
Description
Converts numbers between different number bases. Returns a
string representation of the number N, converted from base from_base
to base to_base.
Returns NULL if any argument is NULL, or if the second or third
argument are not in the allowed range.
The argument N is interpreted as an integer, but may be specified as
an integer or a string. The minimum base is 2 and the maximum base is
36. If to_base is a negative number, N is regarded as a signed number. Otherwise, N is treated as unsigned. CONV() works with 64-bit
precision.
Some shortcuts for this function are also available: BIN(), OCT(),
HEX(), UNHEX(). Also, MariaDB allows binary literal values and
hexadecimal literal values.
BIN is a short form from CONV(value,from,to) where you can convert from base to base
so binary 1001 = 9 as int
here i give the value in decimal (14) and convert it from base 10 to base 2
MariaDB [yourschema]> SELECT CONV(14,10 ,2);
+-----------------+
| CONV(14,10 ,2) |
+-----------------+
| 1110 |
+-----------------+
1 row in set (0.00 sec)
so, if you want to have 0 on the left you can add a value like this
MariaDB [yourschema]> SELECT CONV(8192 + 14,10 ,2);
+------------------------+
| CONV(8192 + 14,10 ,2) |
+------------------------+
| 10000000001110 |
+------------------------+
1 row in set (0.00 sec)
and then you can get n chars from right:
MariaDB [yourschema]> SELECT RIGHT(CONV(8192 + 14,10 ,2),8);
+---------------------------------+
| RIGHT(CONV(8192 + 14,10 ,2),8) |
+---------------------------------+
| 00001110 |
+---------------------------------+
1 row in set (0.40 sec)
MariaDB [yourschema]>
I think you want to use CAST
select CAST(isMale as CHAR) from person;
seeing #Bernd Buffen answer i tried using the convert with +0 and it works , eventhough i dont know why
select CONVERT(isMale +0, char(5)) from person;
Why does this match (it should match (44[0-9]) zero or more times)
mysql> SELECT "tampampam" REGEXP "(44[0-9])*$";
+----------------------------------+
| "tampampam" REGEXP "(44[0-9])*$" |
+----------------------------------+
| 1 |
+----------------------------------+
1 row in set (0.00 sec)
And this does not (it should match 44 followed by ([0-9]) zero or more times
mysql> SELECT "44tampampam" REGEXP "44([0-9])*$";
+------------------------------------+
| "44tampampam" REGEXP "44([0-9])*$" |
+------------------------------------+
| 0 |
+------------------------------------+
1 row in set (0.00 sec)
Well, it is a very strange regex expression.
As for the first case, (44[0-9])*$ means "match a string starting with 44 and then a number from 0 to 9, any number of times up to the end of string". Since "any number" is possible, the string "tampampam" is matched.
As for the second case, 44([0-9])*$ means "match 44, then any number from 0 to 9 (with heavy backtracking), zero or more times, up to the end of string". But after 44 there is "tampampam". No match is due. Remove $, and you'll have a match.
You must use start anchor also to make sure it doesn't match unwanted text:
SELECT "tampampam" REGEXP "^(44[0-9])*$";
+-----------------------------------+
| "tampampam" REGEXP "^(44[0-9])*$" |
+-----------------------------------+
| 0 |
+-----------------------------------+
The first query matches because matching something zero or more times, means that not matching it (ie. matching zero times), is also a match.
The second query does not match, because you have anchored the regular expression to the end of the string, because of the dollar-sign ($). As the end of the string is not the string 44 optionally followed by digits, it does not match.
I see no reason to use *$ in your case. Keep it simple:
SELECT "tampampam" REGEXP "44[0-9]";
=> 0
SELECT "t441ampampam" REGEXP "44[0-9]";
=> 1
SELECT "t441ampampam" REGEXP "^44[0-9]";
=> 0
SELECT "441tampampam" REGEXP "^44[0-9]";
=> 1
So if you need 44 to be the first characters in the string use '^44[0-9]'.
If you don't care that is as simple as '44[0-9]'.
My table filed's value is "<script type="text/javascript"src="http://localhost:8080/db/widget/10217EN/F"></script>",
I want to analyse this string and fetch the id 10217,how to do use mysql regex?
I know python regex group function can return the id 10217,but i'm not familiar with mysql regex.
Please help me,Thank you very much.
MySQL regular expressions do not support subpattern extraction. You will probably have better luck iterating over all of the rows in your database and storing the results in a new column.
As far as I know, you can't use MySQL's REGEXP for substring retrieval; it is designed for use in WHERE clauses and is limited to returning 0 or 1 to indicate failure or success at a match.
Since your pattern is pretty well defined, you can probably retrieve the id with a query that uses SUBSTR and LOCATE. It will be a bit of a mess since SUBSTR wants the start index and the length of the substring (it would be easier if it took the end index). Perhaps you could use TRIM to chop off the unwanted trailing part.
This query get the Id from the field
SELECT substring_index(SUBSTRING_INDEX(testvar,'/',-3),'EN',1) from testtab;
where as testtab - is table name , testvar - is field name
inner substring get string starts with last 3 / which is
mysql> SELECT SUBSTRING_INDEX(testvar,'/',-3) from testtab;
+----------------------------+
| SUBSTRING_INDEX(testvar,'/',-3) |
+----------------------------+
| 10217EN/F"> |
| 10222EN/F"> |
+----------------------------+
2 rows in set (0.00 sec)
outer substring get
mysql> SELECT substring_index(SUBSTRING_INDEX(testvar,'/',-3),'EN',1) from testtab;
+----------------------------------------------------+
| substring_index(SUBSTRING_INDEX(testvar,'/',-3),'EN',1) |
+----------------------------------------------------+
| 10217 |
| 10222 |
+----------------------------------------------------+
2 rows in set (0.00 sec)
What MySQL function can I use?
for example,
What Mysql function can I use?
contains 6 words.
There isn't a built in a function that I know if, but I found this in the comments of MySQL's String Functions documentation:
I was looking for word_count("string") in mysql, finally came up with an user defined function which is very usefull for me, note: I used for actual space.
DROP FUNCTION IF EXISTS word_count;
CREATE FUNCTION word_count (f_string text(5000)) RETURNS smallint(10)
BEGIN
DECLARE new_string text(5000);
WHILE INSTR(f_string,'<space><space>')>0
DO
SET new_string=(select REPLACE(f_string,'<space><space>','<space>'));
SET f_string=new_string;
END WHILE;
RETURN (select LENGTH(TRIM(f_string))-LENGTH(REPLACE(TRIM(f_string),'<space>',''))+1);
END
//
Here is the result
mysql> select word_count("Balaji Devarajan") WORD_COUNT;
+------------+
| WORD_COUNT |
+------------+
| 2 |
+------------+
1 row in set (0.00 sec)
mysql> select word_count(" Balaji Devarajan ") WORD_COUNT;
+------------+
| WORD_COUNT |
+------------+
| 2 |
+------------+
1 row in set (0.00 sec)
mysql> select word_count("Balaji Devarajan") WORD_COUNT;
+------------+
| WORD_COUNT |
+------------+
| 2 |
+------------+
1 row in set (0.01 sec)
There is no function to count words in MySQL (or ANSI SQL, or any other DBMS I'm familiar with).
You could maybe fake it by counting the number of spaces in the text using a string replace:
SELECT LENGTH(colname)-LENGTH(REPLACE(colname, ' ', ''))+1 AS wordcount FROM tablename;
This isn't really a word count but would work as long as every word is separated by exactly one space.
To get better word matching you would need a regex, but there is no regex replace in MySQL so you can't use the replace trick. You could select specifically 6-word long values using a REGEXP/RLIKE match though:
SELECT * FROM tablename WHERE colname RLIKE '^[^[:alnum:]]*[[:alnum:]]+([^[:alnum:]]+[[:alnum:]]+){5}[^[:alnum:]]*$';
Either way, this is slow. It will have to do a string replace or regex match on every row of the table every time you do the query. If number-of-words is a query you are doing often you will want to optimise (denormalise) the table by adding a (possibly indexed) column to store the number of words.