Related
I would need to get value from given regexp.
For example:
> :"postalCode";s:4:"3150";
Is there any way I can extract 3150, from this part of column value. Column value stored serialized objects, so postalCode variable can be null type, that way I should check if positive integer follows ;s:POSITIVE_INT:"postalCodeValue
Use SUBSTRING_INDEX:
SELECT
SUBSTRING(SUBSTRING_INDEX(col, '"', -2), 1,
INSTR(SUBSTRING_INDEX(col, '"', -2), '"') - 1) AS num
FROM yourTable;
This query will extract the last quoted number in your string.
Demo
avoiding regexp you could use some string function eg:
SELECT LENGTH(':"postalCode";s:4:"3150"') - LOCATE(':', REVERSE(':"postalCode";s:4:"3150"'))+1
from dual ;
or
SELECT LENGTH(col_name) - LOCATE(':', REVERSE(col_name))+1
from my_table ;
It also work with 2 times SUBSTRING_INDEX
SELECT
SUBSTRING_INDEX (SUBSTRING_INDEX( ':"postalCode";s:4:"3150";', '"',-2) , '"', 1);
I have table in that I have one field with dash value. Like...
I need to search this with between condition.
For example if I have one value 25 then I need to search the records which include the value 25 like 20-31. In above image there are 6 records which include 25 value. So it should return 6 records.
Please help me in this query ? What would be the query for that ?
You can use MySQL's substring_index() function to easily get the data before and after the dash:
select substring_index(yourcolumn,'-',1) as `lower`, substring_index(yourcolumn,'-',-1) as `upper`
from yourtable
This way you can return the records where a certain value falls between the range:
select * from yourtable
where 25 between substring_index(yourcolumn,'-',1) + 0 and substring_index(yourcolumn,'-',-1) + 0
The + 0 forces MySQL to convert the result of substring_index() to a numeric value before the comparison.
You can use the following solution using SUBSTRING_INDEX:
SELECT *
FROM table_name
WHERE 25 >= CONVERT(SUBSTRING_INDEX(SUBSTRING_INDEX(column_name, '-', 1), '-', -1), UNSIGNED INTEGER)
AND 25 <= CONVERT(SUBSTRING_INDEX(SUBSTRING_INDEX(column_name, '-', 2), '-', -1), UNSIGNED INTEGER)
-- or
SELECT *
FROM table_name
WHERE 25 BETWEEN CONVERT(SUBSTRING_INDEX(SUBSTRING_INDEX(column_name, '-', 1), '-', -1), UNSIGNED INTEGER)
AND CONVERT(SUBSTRING_INDEX(SUBSTRING_INDEX(column_name, '-', 2), '-', -1), UNSIGNED INTEGER)
demo: http://sqlfiddle.com/#!9/4ac7b3/3/0
I recommend you to change your table design. I would split the column using the VARCHAR datatype to two columns using the INTEGER datatype. You can add two new columns with the the following ALTER TABLE commands:
ALTER TABLE table_name ADD colNameA INT;
ALTER TABLE table_name ADD colNameB INT;
To split the values of you current column and update the values to the new columns you can use the following UPDATE command:
UPDATE table_name SET
colNameA = CONVERT(SUBSTRING_INDEX(SUBSTRING_INDEX(column_name, '-', 1), '-', -1), UNSIGNED INTEGER),
colNameB = CONVERT(SUBSTRING_INDEX(SUBSTRING_INDEX(column_name, '-', 2), '-', -1), UNSIGNED INTEGER)
At the end you can remove the VARCHAR column using this ALTER TABLE command:
ALTER TABLE table_name DROP COLUMN col_name
Now you can use the following (simple) query to get the expected results:
SELECT *
FROM table_name
WHERE 25 >= colNameA AND 25 <= colNameB
-- or
SELECT *
FROM table_name
WHERE 25 BETWEEN colNameA AND colNameB
If you want to get values beween 35 and 39, you can use below query,
SELECT
*
FROM
yourtable
WHERE
35 && 39
BETWEEN SUBSTRING_INDEX(tablecolumn, '-', 1) + 0 AND
SUBSTRING_INDEX(tablecolumn, '-', - 1) + 0
I don't know how it possible with MySQL.
But using php it possible to check with range.
For e.g.
// First of all get all record from database.
$search = 10; // Your searching value.
// Loop all rows.
while($rows = mysqli_fetch_array($r)){
$explode = explode("-",$rows['dash']); // For get from-to value.
$range = isset($explode[0])&&isset($explode[1])?range($explode[0],($explode[1]-1)):array(); // For get range.
if(in_array($search,$range)){ // For check searching value is exist or not !
echo "Yes ! I get into ".$rows['dash']; // Do stuff.
}
}
Note: If 10-15 then it will check with 10,11,12,13,14.
According to me if you dont want to change the table structure then,
Just fetch the records as per your other condition, Then from that data check your amount between that field using foreach loop and explode. like
If you have $data as all data
foreach($data as $value){
$new_val=explode(',',$value['new_field']);
if(25 >= $new_val[0] && 25 <= $new_val[1]){
// here create new array
}
}
Updated: Please assume, I will have exactly 4 elements in my version number x.x.x.x
Table xyz (id int, os varchar, version varchar)
id os version
1 mac 1.0.0.4
2 android 1.0.1.2
3 mac 1.0.0.14
4 mac 1.0.0.07
I want to find the maximum version number of each operating system.
select max(version), os from xyz group by os
but in the above data sample, it returns 1.0.0.4 as the highest version of mac, rather than returning 1.0.0.14. Is there any way to fix the above query? I know version is varchar :( If there is NO solution possible, then I can change datatype to other, but that will still not solve the issue.
If the 4 parts in the version are all numbers and not bigger than 255, you can use the INET_ATON() function, and its reverse INET_NTOA():
SELECT INET_NTOA(MAX(INET_ATON(version))), os
FROM xyz
GROUP BY os ;
Tested in SQL-Fiddle
Mysql uses text sort for this field when you try to get max:
SELECT version FROM test ORDER BY VERSION;
1.0.0.14
1.0.0.4
1.0.07
1.0.1.2.4
But even if you try to cast this to integer, you will get
SELECT version FROM test ORDER BY CAST(VERSION AS SIGNED);
1
1
1
1
And this really has a sense. How do you want MySQL to guess, what you want?
MySQL should be used to store data, and you should format it yourself.
A fine solution would be to use several fields for version:
id int, os varchar, versionMajor int, versionMinor int, versionMoreMinor int, versionEvenMoreMinor int
You should be able to sort and to format them as you wish.
It is ugly, but it's doing the job:
select t1.os,t1.version from xyz t1 where (t1.os,
((cast(SUBSTRING_INDEX(t1.version, '.', 1) as unsigned)+1)*1000
+(cast(SUBSTRING_INDEX(SUBSTRING_INDEX(t1.version, '.', -3), '.', 1) as unsigned)+1)*100
+(cast(SUBSTRING_INDEX(SUBSTRING_INDEX(t1.version, '.', -2), '.', 1) as unsigned)+1)*10
+(cast(SUBSTRING_INDEX(t1.version, '.', -1) as unsigned))+1))
=(select t2.os,
max((cast(SUBSTRING_INDEX(t2.version, '.', 1) as unsigned)+1)*1000
+(cast(SUBSTRING_INDEX(SUBSTRING_INDEX(t2.version, '.', -3), '.', 1) as unsigned)+1)*100
+(cast(SUBSTRING_INDEX(SUBSTRING_INDEX(t2.version, '.', -2), '.', 1) as unsigned)+1)*10
+(cast(SUBSTRING_INDEX(t2.version, '.', -1) as unsigned))+1)
from xyz t2 where t2.os=t1.os);
sqlfiddle
What you'd really like to do here is use a SPLIT function, but that's not available in MySQL. However, you can write a user-defined function that will do the same thing, or refactoring this function code into a view.
CREATE FUNCTION SPLIT_STR(
x VARCHAR(255),
delim VARCHAR(12),
pos INT
)
RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
delim, '');
Source.
Additionally, you may want to consider that the reason this is such a pain in the butt is because you're essentially violating first normal form. A version number of the form you specify is actually four distinct values: major version, minor version, revision (or maintenance), and build. Your table structure should use the same format:
Table xyz (id int not null, os varchar not null, version_major int not null, version_minor int not null, version_revision int null, version_build int null)
Then you just use an ORDER BY clause to sort the data. You can use a calculated field or a view to display the formatted version number.
Now, I know why you chose to use a single field. Version numbers are inconsistent, and many version numbers do not include revision or build values, other include letters, etc. You can change the int to a varchar and cover 90% of cases in my experience, however.
You may try to convert string to the integer and get MAX()
SELECT MAX( CONVERT( REPLACE( `version`, '.', '' ), UNSIGNED ) ) from xyz
upd
There are some another way with ending detection, but it doesn't work properly with minor version, maybe you will tune this heavy query to get it works well for you
SELECT `version`,
CONVERT(
CONCAT_WS( '.',
REPLACE( SUBSTRING( `version`, 1, ( CHAR_LENGTH( `version` ) - LOCATE( '.', REVERSE( `version` ) ) ) ), '.', '' ),
SUBSTRING( `version`, 1 + LOCATE( '.', REVERSE( `version` ) ) * -1 )
),
DECIMAL ( 10, 3 )
)
FROM `xyz`
sorry, code improved
Thanks to #ntvf for idea.
This will do what I am looking for.
select a.os, xyz.version from xyz,
(SELECT os, MAX( CONVERT(REPLACE(`version`,'.',''),UNSIGNED)) as version from xyz group by os) a
where
a.os=xyz.os and
CONVERT(REPLACE( xyz.version, '.', '' ), UNSIGNED) = a.version
I'm don't have a lot of knowledge of MySql (or SQL in general) so sorry for the noobness.
I'm trying to update a bunch of String entries this way:
Lets say we have this:
commands.firm.pm.Stuff
Well I want to convert that into:
commands.firm.pm.print.Stuff
Meaning, Add the .print after pm, before "Stuff" (where Stuff can be any Alphanumerical String).
How would I do this with a MySql Query? I'm sure REGEXP has to be used, but I'm not sure how to go about it.
Thanks
Try something like this. It finds the last period and inserts your string there:
select insert(s, length(s) - instr(reverse(s), '.') + 1, 0, '.print')
from (
select 'commands.firm.pm.Stuff' as s
) a
To update:
update MyTable
set MyColumn = insert(MyColumn, length(MyColumn) - instr(reverse(MyColumn), '.') + 1, 0, '.print')
where MyColumn like 'commands.firm.pm.%'
Perhaps use a str_replace to replace commands.firm.pm to commands.firm.pm.print
$original_str = "commands.firm.pm.15hhkl15k0fak1";
str_replace("commands.firm.pm", "commands.firm.pm.print", $original_str);
should output: commands.firm.pm.print.15hhkl15k0fak1
then update your table with the new value...How to do it all in one query (get column value and do the update), I do not know. All I can think of is you getting the column value in one query, doing the replacement above, and then updating the column with the new value in a second query.
To update rows that end in '.Stuff' only:
UPDATE TableX
SET Column = CONCAT( LEFT( CHAR_LENGTH(Column) - CHAR_LENGTH('.Stuff') )
, '.print'
, '.Stuff'
)
WHERE Column LIKE '%.Stuff'
To update all rows - by appending .print just before the last dot .:
UPDATE TableX
SET Column = CONCAT( LEFT( CHAR_LENGTH(Column)
- CHAR_LENGTH(SUBSTRING_INDEX(Column, '.', -1))
)
, 'print.'
, SUBSTRING_INDEX(Column, '.', -1)
)
WHERE Column LIKE '%.%'
I am trying to extract a certain part of a column that is between delimiters.
e.g. find foo in the following
test 'esf :foo: bar
So in the above I'd want to return foo, but all the regexp functions only return true|false,
is there a way to do this in MySQL
Here ya go, bud:
SELECT
SUBSTR(column,
LOCATE(':',column)+1,
(CHAR_LENGTH(column) - LOCATE(':',REVERSE(column)) - LOCATE(':',column)))
FROM table
Yea, no clue why you're doing this, but this will do the trick.
By performing a LOCATE, we can find the first ':'. To find the last ':', there's no reverse LOCATE, so we have to do it manually by performing a LOCATE(':', REVERSE(column)).
With the index of the first ':', the number of chars from the last ':' to the end of the string, and the CHAR_LENGTH (don't use LENGTH() for this), we can use a little math to discover the length of the string between the two instances of ':'.
This way we can peform a SUBSTR and dynamically pluck out the characters between the two ':'.
Again, it's gross, but to each his own.
This should work if the two delimiters only appear twice in your column. I am doing something similar...
substring_index(substring_index(column,':',-2),':',1)
A combination of LOCATE and MID would probably do the trick.
If the value "test 'esf :foo: bar" was in the field fooField:
MID( fooField, LOCATE('foo', fooField), 3);
I don't know if you have this kind of authority, but if you have to do queries like this it might be time to renormalize your tables, and have these values in a lookup table.
With only one set of delimeters, the following should work:
SUBSTR(
SUBSTR(fooField,LOCATE(':',fooField)+1),
1,
LOCATE(':',SUBSTR(fooField,LOCATE(':',fooField)+1))-1
)
mid(col,
locate('?m=',col) + char_length('?m='),
locate('&o=',col) - locate('?m=',col) - char_length('?m=')
)
A bit compact form by replacing char_length(.) with the number 3
mid(col, locate('?m=',col) + 3, locate('&o=',col) - locate('?m=',col) - 3)
the patterns I have used are '?m=' and '&o'.
select mid(col from locate(':',col) + 1 for
locate(':',col,locate(':',col)+1)-locate(':',col) - 1 )
from table where col rlike ':.*:';
If you know the position you want to extract from as opposed to what the data itself is:
$colNumber = 2; //2nd position
$sql = "REPLACE(SUBSTRING(SUBSTRING_INDEX(fooField, ':', $colNumber),
LENGTH(SUBSTRING_INDEX(fooField,
':',
$colNumber - 1)) + 1)";
This is what I am extracting from (mainly colon ':' as delimiter but some exceptions), as column theline255 in table loaddata255:
23856.409:0023:trace:message:SPY_EnterMessage (0x2003a) L"{#32769}" [0081] WM_NCCREATE sent from self wp=00000000 lp=0023f0b0
This is the MySql code (It quickly did what I want, and is straight forward):
select
time('2000-01-01 00:00:00' + interval substring_index(theline255, '.', 1) second) as hhmmss
, substring_index(substring_index(theline255, ':', 1), '.', -1) as logMilli
, substring_index(substring_index(theline255, ':', 2), ':', -1) as logTid
, substring_index(substring_index(theline255, ':', 3), ':', -1) as logType
, substring_index(substring_index(theline255, ':', 4), ':', -1) as logArea
, substring_index(substring_index(theline255, ' ', 1), ':', -1) as logFunction
, substring(theline255, length(substring_index(theline255, ' ', 1)) + 2) as logText
from loaddata255
and this is the result:
# LogTime, LogTimeMilli, LogTid, LogType, LogArea, LogFunction, LogText
'06:37:36', '409', '0023', 'trace', 'message', 'SPY_EnterMessage', '(0x2003a) L\"{#32769}\" [0081] WM_NCCREATE sent from self wp=00000000 lp=0023f0b0'
This one looks elegant to me. Strip all after n-th separator, rotate string, strip everything after 1. separator, rotate back.
select
reverse(
substring_index(
reverse(substring_index(str,separator,substrindex)),
separator,
1)
);
For example:
select
reverse(
substring_index(
reverse(substring_index('www.mysql.com','.',2)),
'.',
1
)
);
you can use the substring / locate function in 1 command
here is a mice tutorial:
http://infofreund.de/mysql-select-substring-2-different-delimiters/
The command as describes their should look for u:
**SELECT substr(text,Locate(' :', text )+2,Locate(': ', text )-(Locate(' :', text )+2)) FROM testtable**
where text is the textfield which contains "test 'esf :foo: bar"
So foo can be fooooo or fo - the length doesnt matter :).