mysql SUBSTRING() and LOCATE() - mysql

I am using mysql's SUBSTRING() function and LOCATE() to capture "n" characters before and after some string.
For example, using the string "apple". When I query it works fine except if the string "apple" is towards the beginning of the string since 10 characters before may be non-existent:
http://sqlfiddle.com/#!9/f41f8d/5
CREATE TABLE demo (name varchar(1000));
INSERT INTO demo (name) VALUES
("An apple a day keeps the doctor away"),
("A doctor a day keeps the apple away from the doctor");
SELECT SUBSTRING(
`name`,
LOCATE("apple",`name`) - 10, /* from 10 characters before 'string'*/
(25) /* to 10 characters after the 5 strlen string (so 10 + 5 + 10) */
)
FROM demo
WHERE name like '%apple%'
Results
| r away |
| keeps the apple away from |
The second results is as expected, but the first - I would like it to start at the beginning of the string until 10 characters after "apple".
What's wrong with my query or how can I fix it? I'm also queries millions of rows so I assume a sub-query to check if it's position is less than "string"'s length isn't performant?

Try with this:
SELECT SUBSTRING(
`name`,
GREATEST(LOCATE("apple",`name`) - 10, 1), /* from 10 characters before 'string'*/
LEAST(25, LENGTH(name) - GREATEST(LOCATE("apple",`name`) - 10, 1)) /* to 10 characters after the 5 strlen string (so 10 + 5 + 10) */
)
FROM demo
WHERE name like '%apple%'

Something like this:
SELECT SUBSTRING(name,
GREATEST(1, LOCATE('apple', name) - 10),
15 + LEAST(LOCATE('apple', name), 10)
)
FROM demo
WHERE name like '%apple%'

Related

Compairing two strings in MYSQL

I have a sequence of 20 numbers from 0 to 2, I want to compare this string with other sequences saved in my database, the problem is that the lenght of the strings saved on the database fluctuates.Also the comparison needs to be done from the end to the start.
Example of what I want:
20 digits string:
'1,1,2,1,2,1,0,1,2,1,2,1,0,1,2,1,1,1,2,1'
couple of strings saved in the database:
1 - '1,1,2,1'
2 - '2,1,2,2,2,2'
3 - '2,1'
4 - '1,1,2,1,2,1'
In this case the query would return the 1 and 3 only
create table mytable ( s varchar(60) );
insert into mytable values
('1,1,2,1'),
('2,1,2,2,2,2'),
('2,1'),
('1,1,2,1,2,1');
set #x = '1,1,2,1,2,1,0,1,2,1,2,1,0,1,2,1,1,1,2,1';
select s from mytable
where right(#x, length(s)) = s;
Output:
s
1,1,2,1
2,1
Fiddle: https://www.db-fiddle.com/f/r5m2hPbnmUu5VQfYvMVtir/0
You could use a LIKE trick here. For example, to check for the first string 1,1,2,1:
SELECT *
FROM yourTable
WHERE ',1,1,2,1,2,1,0,1,2,1,2,1,0,1,2,1,1,1,2,1,' LIKE '%,1,1,2,1,%';

MySQL - Return from a string the leftmost characters from 2 different characters

I have a database with some codes seperated by / or -, I want to show the left side only, this is an example of the data:
45/84
12/753
68-53
15742-845
2/556
So, i want to get this:
45
12
68
15742
2
I tried using LEFT(), but this search for 1 character only, and returns a warning if the character is not found, this is what LEFT(field,'/') returns.
45
12
(WARNING)
(WARNING)
2
So, what about a REGEXP?
an IF?
any way to ignore from the first non numeric character?
I dont' have more ideas...
Thank you!
Try this:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(col, '-', 1), '/', 1)
FROM mytable
Demo here
You can do it with this statement. Replace the string '15742/845' with your fieldname
SELECT SUBSTRING_INDEX( REPLACE('15742/845','/','-'), '-', 1)

MYSQL add 1 to max value in substring_index

I'm trying to add 1 to my max field value in mysql query:
SELECT MAX(SUBSTRING_INDEX(0001-14-A,'-',1)) AS prefix;
RESULT:
prefix
------
0001
However when i do like this:
SELECT MAX(SUBSTRING_INDEX(0001-14-A,'-',1)) + 1 AS prefix;
RESULT:
prefix
------
2
How to remain the value format to ****? Please advise.
First, you are missing single quotes:
SELECT MAX(SUBSTRING_INDEX('0001-14-A', '-', 1)) + 1 AS prefix
When you add one to the value, it is converted to an integer. To get a string back, you need to pad it:
SELECT LPAD(MAX(SUBSTRING_INDEX('0001-14-A', '-', 1)) + 1, 4, '0') AS prefix

Natural Sorting SQL ORDER BY

Can anyone lend me a hand as to what I should append to my ORDER BY statement to sort these values naturally:
1
10
2
22
20405-109
20405-101
20404-100
X
Z
D
Ideally I'd like something along the lines of:
1
2
10
22
20404-100
20405-101
20405-109
D
X
Z
I'm currently using:
ORDER BY t.property, l.unit_number
where the values are l.unit_number
I've tried doing l.unit_number * 1 and l.unit_number + 0 but they haven't worked.
Should I be doing sort of ORDER conditional, such as Case When IsNumeric(l.unit_number)?
Thank you.
This will do it:
SELECT value
FROM Table1
ORDER BY value REGEXP '^[A-Za-z]+$'
,CAST(value as SIGNED INTEGER)
,CAST(REPLACE(value,'-','')AS SIGNED INTEGER)
,value
The 4 levels of the ORDER BY:
REGEXP assigns any alpha line a 1 and non-alphas a 0
SIGNED INT Sorts all of the numbers by the portion preceding the dash.
SIGNED INT after removing the dash sorts any of the items with the same value before the dash by the portion after the dash. Potentially could replace number 2, but wouldn't want to treat 90-1 the same as 9-01 should the case arise.
Sorts the letters alphabetically.
Demo: SQL Fiddle

Mysql select all that match a number in string

Assume my table column contains the following 2 string rows:
1, 5, 2, 31, 12, 1212, 111
21, 25, 32, 43, 112, 212, 311
I need a query to select a row that contains number 1 and contains number 2
My Query is:
SELECT *
FROM MyTable
WHERE My_String LIKE '%1%' AND My_String LIKE '%2%'
now this returns both of the rows when i want it to return only the first row.
It selects second row because numbers 21, 25, 32, 112, 212, 311 also contain number 1 and 2.
My question is how do i select all those rows where numbers 1 and 2 are contained in a string but not in 2-3 digit numbers. I want it to match strictly to those 1 and 2
http://www.sqlfiddle.com/#!2/b082d/5
select * from testtable
where instr(concat(', ', longstring, ', '), ', 2,') >0;
select * from testtable
where instr(concat(', ', longstring, ', '), ', 1,') >0
and instr(concat(', ', longstring, ', '), ', 2,') >0;
You can use a regular expression. [[:<:]] is a beginning word boundary and [[:>:]] is end word boundary.
SELECT * FROM MyTable
WHERE My_String RLIKE '[[:<:]]1[[:>:]]'
AND My_String RLIKE '[[:<:]]2[[:>:]]'
You have few options:
1- As mentioned in a comment on the main post, change the structure and don't store concatenated strings
2- write a function that splits the string and checks if the numbers 1 and 2 appear in the tokens after splitting.
3- write "where" clause that captures every possibility of appearance for a string:
a string can appear in the beginning, middle, end of the list or be the only element in the list. the last one, is not important since you require 1 and 2 to appear in a row, and therefore a list String containing a single element should be eliminated. so:
select *
from MyTable
where (My_String like '1,%' or My_String like '%, 1,%' or My_String like '%, 1')
and (My_String like '2,%' or My_String like '%, 2,%' or My_String like '%, 2')