MySQL Query: limit result respecting substring count - mysql

I have a table like this
ROW ID | CONTENT
------------------------------------------------
test1 | foo, foo, foo
test2 | bar, bar
test3 | foo, foo
test4 | foo, foo, foo, foo
What I want to achieve is query that gives me the rows but limiting it respecting the occurrences of a substring.
Some examples could be:
Limit result to 3 "foo" occurrences -> should return test1
Limit result to 4 "foo" occurrences -> should return test1 and test3
Limit result to 100 "foo" occurrences -> should return test1,test3, test4
Limit result to 7 "foo" occurrences -> should also return test1,test3, test4
Is there any way to do this? Thanks in advance!
P.S. : I should have mentioned that the ',' can be any string without a predictable length.

SQL Fiddle
MySQL 5.5.32 Schema Setup:
CREATE TABLE Table1
(`ROW ID` varchar(5), `CONTENT` varchar(18))
;
INSERT INTO Table1
(`ROW ID`, `CONTENT`)
VALUES
('test1', 'foo, foo, foo'),
('test2', 'bar, bar'),
('test3', 'foo, foo'),
('test4', 'foo, foo, foo, foo')
;
Query 1:
SELECT *
FROM Table1
WHERE ((LENGTH(CONTENT) -
LENGTH(REPLACE(CONTENT, ',', ''))) + 1) < 3
AND SUBSTRING(CONTENT,1,LENGTH('FOO')) = 'FOO'
Results:
| ROW ID | CONTENT |
|--------|----------|
| test3 | foo, foo |
EDIT :
If you are dealing with phrases, it could look like this :
SQL Fiddle
MySQL 5.5.32 Schema Setup:
CREATE TABLE Table1
(`ROW ID` varchar(5), `CONTENT` varchar(48))
;
INSERT INTO Table1
(`ROW ID`, `CONTENT`)
VALUES
('test1', 'foo de foo refe foo'),
('test2', 'bar re bar'),
('test3', 'foo rer ef foo'),
('test4', 'foo rer foo fsdfs foo dfsfe foo')
;
Query 1:
SELECT *
FROM Table1
WHERE (LENGTH(CONCAT(' ',CONTENT,' ')) -
LENGTH(REPLACE(CONCAT(' ',UPPER(CONTENT),' '),
CONCAT(' ','FOO',' '), '')))
/(LENGTH('FOO')+2) < 3 AND
CONCAT(' ',CONTENT,' ') LIKE CONCAT('% ','FOO',' %')
Results:
| ROW ID | CONTENT |
|--------|----------------|
| test3 | foo rer ef foo |

You want to count the number of foos in the list. This is pretty easy:
select t.*
from t
where (char_length(concat(', ', content, ', ')) -
char_length(replace(concat(', ', content, ', '), ', foo, ', '1234567'))
) = 3;
The idea is to replace 'foo' with something that has one fewer character. However, you might want to be careful with 'foobars' and 'barfood' and other strings that could cause a false positive. So, this version just puts the separators at the beginning and end of the string.
Once you have this information, you can do whatever comparisons you would like.

MySQL unfortunately doesn't have any bulit-in function for what you want to do. You need something like SUBSTRING_COUNT, which doesn't exist. What you can do is, based on this answer` calculate that value.
Something like this might work:
SELECT rowid,
(LENGTH(content) - LENGTH(REPLACE(content, 'foo', ''))) / LENGTH('foo') AS cnt
FROM thetable
HAVING cnt > 0 && cnt < 4;
DEMO: http://sqlfiddle.com/#!2/10599/7

Related

Insert a "-" after third character for whole column in SQL

I have a column (Name is the header of the column) with 8 character numbers. I am looking for a query to insert a '-' after the third character of every row of data.
For example if I have:
| Name |
|----------|
| 99912345 |
I want to get:
| Name |
|-----------|
| 999-12345 |
I have tried the following:
SELECT INSERT(name, 3, 0, "-");
The database I am using is called temp.Test1 on mySQL
You were close:
SELECT INSERT(name, 4, 0, '-') from mytable
Here is the demo:
DEMO
In MySQL, use substring to divide your value and concat to put it back together.
set #test = 99912345;
select concat(
substring(#test, 1, 3),
'-',
substring(#test, 4)
);
gives 999-12345
Edit: You can also make a virtual column which does this for you, and just retrieve the column in your application.
alter table `test1`
add `formattedName` varchar(9) as (
concat(
substring(`name`, 1, 3),
'-',
substring(`name`, 4)
)
);
select `formattedName` from `test`
See demo

How to replace all the digits before hyphen with a new digit using MySQL? [duplicate]

I have a table called myTable which has a column called col1. This column contains data in this format: (1 or 2 digits)(hyphen)(8 digits).
I want to replace all the data in this column and replace everything before hyphen with 4, so this is an example:
--------------------------------
| old values | New Values |
--------------------------------
| 1-654283568 => 4-654283568 |
| 2-467862833 => 4-467862833 |
| 8-478934293 => 4-478934293 |
| 12-573789475 => 4-573789475 |
| 16-574738575 => 4-574738575 |
--------------------------------
I am using MySQL 5.7.19, I believe REGEXP_REPLACE is available in MySQL Version 8+... not sure how this can be achieved?
You don't need regex; you can use SUBSTRING_INDEX to extract everything after the hyphen and concatenate 4- to that:
UPDATE myTable
SET col1 = CONCAT('4-', SUBSTRING_INDEX(col1, '-', -1))
Demo on dbfiddle
This will work regardless of the number of characters after the hyphen.
Looking to your pattern seem you could avoid regexp
update myTable
set col1 = concat('4-', right(col1,8))
or
update myTable
set col1 = concat('4', right(col1,9))
Try this:
UPDATE testing SET val=REPLACE(val,SUBSTRING(val,1,LOCATE('-',val)),'4-');
Fiddle here :https://www.db-fiddle.com/f/4mU5ctLh8NB9iKSKZF9Ue2/2
Using LOCATE to find '-' position then use SUBSTRING to get only the front part of the '-'.
SELECT CONCAT( #new_prefix, SUBSTRING(old_value FROM LOCATE('-', old_value)) ) AS new_value
UPDATE sourcetable
SET fieldname = CONCAT( '4', SUBSTRING(fieldname FROM LOCATE('-', fieldname)) )
WHERE LOCATE('-', fieldname)
/* AND another conditions */

How to replace a regex pattern in MySQL

I have a table called myTable which has a column called col1. This column contains data in this format: (1 or 2 digits)(hyphen)(8 digits).
I want to replace all the data in this column and replace everything before hyphen with 4, so this is an example:
--------------------------------
| old values | New Values |
--------------------------------
| 1-654283568 => 4-654283568 |
| 2-467862833 => 4-467862833 |
| 8-478934293 => 4-478934293 |
| 12-573789475 => 4-573789475 |
| 16-574738575 => 4-574738575 |
--------------------------------
I am using MySQL 5.7.19, I believe REGEXP_REPLACE is available in MySQL Version 8+... not sure how this can be achieved?
You don't need regex; you can use SUBSTRING_INDEX to extract everything after the hyphen and concatenate 4- to that:
UPDATE myTable
SET col1 = CONCAT('4-', SUBSTRING_INDEX(col1, '-', -1))
Demo on dbfiddle
This will work regardless of the number of characters after the hyphen.
Looking to your pattern seem you could avoid regexp
update myTable
set col1 = concat('4-', right(col1,8))
or
update myTable
set col1 = concat('4', right(col1,9))
Try this:
UPDATE testing SET val=REPLACE(val,SUBSTRING(val,1,LOCATE('-',val)),'4-');
Fiddle here :https://www.db-fiddle.com/f/4mU5ctLh8NB9iKSKZF9Ue2/2
Using LOCATE to find '-' position then use SUBSTRING to get only the front part of the '-'.
SELECT CONCAT( #new_prefix, SUBSTRING(old_value FROM LOCATE('-', old_value)) ) AS new_value
UPDATE sourcetable
SET fieldname = CONCAT( '4', SUBSTRING(fieldname FROM LOCATE('-', fieldname)) )
WHERE LOCATE('-', fieldname)
/* AND another conditions */

Count the number of occurrences of a string in a VARCHAR field?

I have a table like this:
TITLE | DESCRIPTION
------------------------------------------------
test1 | value blah blah value
test2 | value test
test3 | test test test
test4 | valuevaluevaluevaluevalue
I am trying to figure out how to return the number of times a string occurs in each of the DESCRIPTION's.
So, if I want to count the number of times 'value' appears, the sql statement will return this:
TITLE | DESCRIPTION | COUNT
------------------------------------------------------------
test1 | value blah blah value | 2
test2 | value test | 1
test3 | test test test | 0
test4 | valuevaluevaluevaluevalue | 5
Is there any way to do this? I do not want to use php at all, just mysql.
This should do the trick:
SELECT
title,
description,
ROUND (
(
LENGTH(description)
- LENGTH( REPLACE ( description, "value", "") )
) / LENGTH("value")
) AS count
FROM <table>
A little bit simpler and more effective variation of #yannis solution:
SELECT
title,
description,
CHAR_LENGTH(description) - CHAR_LENGTH( REPLACE ( description, 'value', '1234') )
AS `count`
FROM <table>
The difference is that I replace the "value" string with a 1-char shorter string ("1234" in this case). This way you don't need to divide and round to get an integer value.
Generalized version (works for every needle string):
SET #needle = 'value';
SELECT
description,
CHAR_LENGTH(description) - CHAR_LENGTH(REPLACE(description, #needle, SPACE(LENGTH(#needle)-1)))
AS `count`
FROM <table>
try this:
select TITLE,
(length(DESCRIPTION )-length(replace(DESCRIPTION ,'value','')))/5 as COUNT
FROM <table>
SQL Fiddle Demo
In SQL SERVER, this is the answer
Declare #t table(TITLE VARCHAR(100), DESCRIPTION VARCHAR(100))
INSERT INTO #t SELECT 'test1', 'value blah blah value'
INSERT INTO #t SELECT 'test2','value test'
INSERT INTO #t SELECT 'test3','test test test'
INSERT INTO #t SELECT 'test4','valuevaluevaluevaluevalue'
SELECT TITLE,DESCRIPTION,Count = (LEN(DESCRIPTION) - LEN(REPLACE(DESCRIPTION, 'value', '')))/LEN('value')
FROM #t
Result
TITLE DESCRIPTION Count
test1 value blah blah value 2
test2 value test 1
test3 test test test 0
test4 valuevaluevaluevaluevalue 5
I don't have MySQL install, but goggled to find the Equivalent of LEN is LENGTH while REPLACE is same.
So the equivalent query in MySql should be
SELECT TITLE,DESCRIPTION, (LENGTH(DESCRIPTION) - LENGTH(REPLACE(DESCRIPTION, 'value', '')))/LENGTH('value') AS Count
FROM <yourTable>
Please let me know if it worked for you in MySql also.
Here is a function that will do that.
CREATE FUNCTION count_str(haystack TEXT, needle VARCHAR(32))
RETURNS INTEGER DETERMINISTIC
BEGIN
RETURN ROUND((CHAR_LENGTH(haystack) - CHAR_LENGTH(REPLACE(haystack, needle, ""))) / CHAR_LENGTH(needle));
END;
This is the mysql function using the space technique (tested with mysql 5.0 + 5.5):
CREATE FUNCTION count_str( haystack TEXT, needle VARCHAR(32))
RETURNS INTEGER DETERMINISTIC
RETURN LENGTH(haystack) - LENGTH( REPLACE ( haystack, needle, space(char_length(needle)-1)) );
SELECT
id,
jsondata,
ROUND (
(
LENGTH(jsondata)
- LENGTH( REPLACE ( jsondata, "sonal", "") )
) / LENGTH("sonal")
)
+
ROUND (
(
LENGTH(jsondata)
- LENGTH( REPLACE ( jsondata, "khunt", "") )
) / LENGTH("khunt")
)
AS count1 FROM test ORDER BY count1 DESC LIMIT 0, 2
Thanks Yannis, your solution worked for me and here I'm sharing same solution for multiple keywords with order and limit.
In most cases, these functions are LENGTH and REPLACE, respectively (SQL Server users will use the built-in function LEN rather than LENGTH):
Example, count num of comma in the string "10,CLARK,MANAGER"
select (length('10,CLARK,MANAGER')-
length(replace('10,CLARK,MANAGER',',','')))/length(',')
as cnt from t1

Detect if value is number in MySQL

Is there a way to detect if a value is a number in a MySQL query? Such as
SELECT *
FROM myTable
WHERE isANumber(col1) = true
You can use Regular Expression too... it would be like:
SELECT * FROM myTable WHERE col1 REGEXP '^[0-9]+$';
Reference:
http://dev.mysql.com/doc/refman/5.1/en/regexp.html
This should work in most cases.
SELECT * FROM myTable WHERE concat('',col1 * 1) = col1
It doesn't work for non-standard numbers like
1e4
1.2e5
123. (trailing decimal)
If your data is 'test', 'test0', 'test1111', '111test', '111'
To select all records where the data is a simple int:
SELECT *
FROM myTable
WHERE col1 REGEXP '^[0-9]+$';
Result: '111'
(In regex, ^ means begin, and $ means end)
To select all records where an integer or decimal number exists:
SELECT *
FROM myTable
WHERE col1 REGEXP '^[0-9]+\\.?[0-9]*$'; - for 123.12
Result: '111' (same as last example)
Finally, to select all records where number exists, use this:
SELECT *
FROM myTable
WHERE col1 REGEXP '[0-9]+';
Result: 'test0' and 'test1111' and '111test' and '111'
SELECT * FROM myTable
WHERE col1 REGEXP '^[+-]?[0-9]*([0-9]\\.|[0-9]|\\.[0-9])[0-9]*(e[+-]?[0-9]+)?$'
Will also match signed decimals (like -1.2, +0.2, 6., 2e9, 1.2e-10).
Test:
drop table if exists myTable;
create table myTable (col1 varchar(50));
insert into myTable (col1)
values ('00.00'),('+1'),('.123'),('-.23e4'),('12.e-5'),('3.5e+6'),('a'),('e6'),('+e0');
select
col1,
col1 + 0 as casted,
col1 REGEXP '^[+-]?[0-9]*([0-9]\\.|[0-9]|\\.[0-9])[0-9]*(e[+-]?[0-9]+)?$' as isNumeric
from myTable;
Result:
col1 | casted | isNumeric
-------|---------|----------
00.00 | 0 | 1
+1 | 1 | 1
.123 | 0.123 | 1
-.23e4 | -2300 | 1
12.e-5 | 0.00012 | 1
3.5e+6 | 3500000 | 1
a | 0 | 0
e6 | 0 | 0
+e0 | 0 | 0
Demo
Returns numeric rows
I found the solution with following query and works for me:
SELECT * FROM myTable WHERE col1 > 0;
This query return rows having only greater than zero number column that col1
Returns non numeric rows
if you want to check column not numeric try this one with the trick (!col1 > 0):
SELECT * FROM myTable WHERE !col1 > 0;
This answer is similar to Dmitry, but it will allow for decimals as well as positive and negative numbers.
select * from table where col1 REGEXP '^[[:digit:]]+$'
use a UDF (user defined function).
CREATE FUNCTION isnumber(inputValue VARCHAR(50))
RETURNS INT
BEGIN
IF (inputValue REGEXP ('^[0-9]+$'))
THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END;
Then when you query
select isnumber('383XXXX')
--returns 0
select isnumber('38333434')
--returns 1
select isnumber(mycol) mycol1, col2, colx from tablex;
-- will return 1s and 0s for column mycol1
--you can enhance the function to take decimals, scientific notation , etc...
The advantage of using a UDF is that you can use it on the left or right side of your "where clause" comparison. this greatly simplifies your SQL before being sent to the database:
SELECT * from tablex where isnumber(columnX) = isnumber('UnkownUserInput');
hope this helps.
Another alternative that seems faster than REGEXP on my computer is
SELECT * FROM myTable WHERE col1*0 != col1;
This will select all rows where col1 starts with a numeric value.
Still missing this simple version:
SELECT * FROM myTable WHERE `col1` + 0 = `col1`
(addition should be faster as multiplication)
Or slowest version for further playing:
SELECT *,
CASE WHEN `col1` + 0 = `col1` THEN 1 ELSE 0 END AS `IS_NUMERIC`
FROM `myTable`
HAVING `IS_NUMERIC` = 1
You can use regular expression for the mor detail https://dev.mysql.com/doc/refman/8.0/en/regexp.html
I used this ^([,|.]?[0-9])+$. This is allows handle to the decimal and float number
SELECT
*
FROM
mytable
WHERE
myTextField REGEXP "^([,|.]?[0-9])+$"
I recommend: if your search is simple , you can use `
column*1 = column
` operator interesting :) is work and faster than on fields varchar/char
SELECT * FROM myTable WHERE column*1 = column;
ABC*1 => 0 (NOT EQU **ABC**)
AB15*A => 15 (NOT EQU **AB15**)
15AB => 15 (NOT EQU **15AB**)
15 => 15 (EQUALS TRUE **15**)
SELECT * FROM myTable WHERE sign (col1)!=0
ofcourse sign(0) is zero, but then you could restrict you query to...
SELECT * FROM myTable WHERE sign (col1)!=0 or col1=0
UPDATE: This is not 100% reliable, because "1abc" would return sign of
1, but "ab1c" would return zero... so this could only work for text that does not begins with numbers.
you can do using CAST
SELECT * from tbl where col1 = concat(cast(col1 as decimal), "")
I have found that this works quite well
if(col1/col1= 1,'number',col1) AS myInfo
Try Dividing /1
select if(value/1>0 or value=0,'its a number', 'its not a number') from table