MySQL Logical Operators in a field with text and integers - mysql

I have a table that looks like:
ATTRIBUTE1 | ATTRIBUTE2
weight: 190| height: 175
ctr: 400 | dmd: 19
Is it possible to do comparative operations on these fields?
Like, if I wanted to find everyone with a weight less than 200, what would the syntax look like for that? I figure the query would look like the following, if there were no text in the field:
SELECT * FROM mytable WHERE attribute1 < '200'
But since the field has the defining text "weight:", I'm not quite sure how to do this.

Rather
CAST(SUBSTRING(attribute1, INSTR(attribute, ': ') AS SIGNED)
because the value contains the string in the beginning.
Basically you do like this:
Find the index of ': ' and use it as a substring for the value (to skip everything until the actual number). Then you cast it to an Int
(maybe you need to add a +1 to INSTR. I'm not sure since i don't have a mysql client right here

where cast(substring(ATTRIBUTE1, instr(ATTRIBUTE1, ': ')+1 ) as unsigned) <200
alternative:
where cast(replace(Field_2, 'weight: ', '') as unsigned) > 180

Related

How to extract specifc part from a string in MySQL

I am trying to extract a specifc part from a string in MySQL, however, I am unable to extract it correctly.
The pattern is the following:
-MB|{field_1}-AA|{field_2}-BB|{field_3}
This is the example
-MB|string1-AA|string2-BB|string3
I've written the following code to extract the last field, however it is not dynamic, and will only work, when we have a specific number of letters/numbers:
SELECT
test_string,
SUBSTRING(test_string, LOCATE( '|', test_string) + 1 - LOCATE( '|', test_string) - 9) as string3
FROM test_table;
The output is the whole string and then just the last part of it:
string3
Having this said, can someone suggest a syntax that I can use in order to extract:
the values between the 1st | and second |
the value between the 2nd | and the 3rd |
and a better way to extract everything after the 3rd |
Thank you in advance!
If you're going for the last string only, you can REVERSE() the string first then locate | and then use it to do SUBSTRING() on the reversed string.. THEN reverse it again to get the original string. There are three REVERSE() in total if you're going with SUBSTRING() without a subquery:
SELECT test_string,
REVERSE(SUBSTRING(REVERSE(test_string),1,LOCATE('|',REVERSE(test_string))-1))
FROM test_table;
If you're using a subquery, you can reduce the usage of REVERSE() to two, albeit with a longer query:
SELECT test_string,
REVERSE(SUBSTRING(rvstr,1,LOCATE('|',rvstr)-1))
FROM
(SELECT test_string,
REVERSE(test_string) rvstr
FROM test_table) a;
But you can avoid all that and just use SUBSTRING_INDEX
SELECT test_string,
SUBSTRING_INDEX(test_string, '|', -1)
FROM test_table;
You can use the same function to extract other string separated by the delimiter using something like this:
SELECT test_string,
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',1),'|',-1) AS 'Str1',
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',2),'|',-1) AS 'Str2',
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',3),'|',-1) AS 'Str3'
FROM test_table;
As for "way to extract everything after the 3rd", I think it's a bit tricky but maybe:
SELECT test_string,
Str1,Str2,Str3,
SUBSTRING(test_string,LENGTH(CONCAT(Str1,Str2,Str3))+4) AS 'StrAfter3rd'
FROM
(SELECT test_string,
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',1),'|',-1) AS 'Str1',
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',2),'|',-1) AS 'Str2',
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',3),'|',-1) AS 'Str3'
FROM test_table) v;
Getting the LENGTH() of the concatenated results of Str1 to Str3 with 3 of the original | re-added and + the last | before the 4th string (+4 in total), then use it for the SUBSTRING().
Demo fiddle

sql extract only numeric value from column

I have a column called' memo_line_2',the value format is like :'$3000.00 (card limit increase)',how can I only extract numeric value from the column?Thanks
example:
'$3000.00 (card limit increase)' -> 3000
'$5000.00 (card limit increase)' -> 5000
'$12000.00 (card limit increase)' ->12000
You could use REGEXP_SUBSTR() for this:
SELECT REGEXP_SUBSTR(tmp.`value`, '[0-9]+') as `new_value`
FROM (SELECT '$3000.00' as `value` UNION ALL
SELECT '$5000.00' as `value` UNION ALL
SELECT '$12000.00' as `value`) tmp
Returns:
new_value
---------
3000
5000
12000
If you would like to keep everything after the decimal, use '[0-9.]+' as your regular expression filter.
If your data will be always in this format you can use below query to select the data between $ and . :
SELECT substring_index(substring_index(memo_line_2, '$', -1), '.', 1)
FROM your_table;
Refrence: MySQL substring between two strings
You can use:
select regexp_substr(col, '[0-9]+[.]?[0-9]*')
This will extract the digits with the cents. You can then convert to an integer or numeric:
select cast(regexp_substr(col, '[0-9]+[.]?[0-9]*') as unsigned)
It can be done by making a custom function in your sql query
Take a look at:
https://stackoverflow.com/a/37269038/16536522

SQL Is there a way to link two tables with the same value but different formats?

So I have two columns from two different databases that I would like to link.
Problem is that my first column outputs the numbers with this format "1 789 987" and my second column outputs the data "0000000001789987"
How can I write my WHERE sql forumla to idententify these as matching?
Ok so I pulled out the qrys to excel to provide you with more information.
Here are the different tables.
Looks like Tbl2 has NUM column set to text. And even though the QRY in the program gave spaces to the numbers in Tbl1 it looks like the qry removed them shrug
SELECT *
FROM "Tbl1","Tbl2"
WHERE "Tbl1"."num" = "Tbl2"."num"
AND "Tbl1"."Date" BETWEEN '2019-01-21' AND '2019-01-25'
I hope the information became abit clearer. I'm new to SQL and Stackoverflow, i'll try and improve my questions information in the future.
Well, to transform format 1 to format 2 you can try something like this :
set #format1 = "1 789 987";
set #format2 = "0000000001789987";
select LPAD(REPLACE(#format1, ' ', ''), 16, "0") as format1, #format2 as format2
Output is :
====================================
format1 | format2
====================================
0000000001789987 | 0000000001789987
This way format1 looks like format2 if you test it. The REPLACE remove the ' ' and the LPAD will fill the string with 0 untill the string is 16 char length like the format2.
So you can use this in you WHERE condition :
...WHERE LPAD(REPLACE(your_first_column, ' ', ''), 16, "0") = your_other_column
Now you can try to transform both column in int too, you didn't provide lot of information about those format so hard to find the best solution !
This cast may fit for you:
NOTE: tbl1 contains ids like: 1 789 987
select *
from tbl1 join tbl2 on (
cast( -- casts to integer
replace(tbl1.text_id, ' ', '') -- removes whitespaces
as int) =
tbl2.numeric_id -- join on second table
)
In any case please provide sample data and a testable example what you did and the results you need

MySQL sorting with alphanumeric prefix

I've got a database with a column that contains the following data:
aaa-1
aaa-2
aaa-3
...
aaa-10
aaa-11
...
aaa-100
aaa-101
...
aaa-1000
When I query and sort the data in ascending order, I get:
aaa-1
aaa-10
aaa-11
...
aaa-100
aaa-101
...
aaa-1000
...
aaa-2
...
aaa-3
Is this actually the correct (machine) way of sorting? Is the order being screwed up because of the aaa- prefix? How do I go about sorting this the way a human would (ie something that looks like the first snippet)?
P.S. If the problem does lie in the prefix, is there a way to remove it and sort with just the numeric component?
P.P.S. It's been suggested to me that I should just change my data and add leading zeroes like aaa-0001 and aaa-0002, etc. However, I'm loathe to go that method as each time the list goes up an order of 10, I'd have to reformat this column.
Thank you all in advance! :)
You can extract the number part, convert it to numeric data type and then do an ORDER BY:
SELECT mytable.*,
CAST(SUBSTRING_INDEX(mycolumn, '-', - 1) AS UNSIGNED) mycolumnintdata
FROM
mytable
ORDER BY mycolumnintdata;
If there are expressions which does not match number, the CAST function would return 0 and those records would be displayed first. You may handle this separately if needed.
I had a similar issue and the trick that did it for me was this one
*"ORDER BY LENGTH(column_name), column_name
As long as the non-numeric part of the value is the same length, this will sort 1 before 10, 10 before 100, etc."*
as given by Andreas Bergström on this question.
Hope that helps someone.
this is the alphabetical order,
you want numerical order,
for do this you must in the ORDER BY clause
trim the costant "aaa-" part
convert it in number
convert(SUBSTRING(val, 3), integer)
I will give you a sample sorting. Not based on your data sample, but this could help you out.
Say you have data like this :
id
----
1
2
6
10
13
when you do ORDER BY id ASC would return :
id
----
1
10
13
2
6
I suggest, use LPAD.
This query : SELECT LPAD('12',5,'0') return 00012
So when you have table data like I provide above, you can sort them like this :
SELECT * FROM TABLE
ORDER BY LPAD(ID,7,'0') ASC
Based on your data.
SELECT SUBSTR('aaa-100',5,LENGTH('aaa-100') - 3) return 100
So, SELECT LPAD( SUBSTR('aaa-100',5,LENGTH('aaa-100') - 3), 7, '0') return 00000100
So you can combine string function such as SUBSTR and LPAD. Do have any clue now?

Convert text to float, when text comes in different formats

I want to store a text as a float. My problem is, that this text comes in different formats , and I cannot influence that. My TEXT column contains strings like
357000
218000.56
500.000.00
I don't have a problem converting the first two strings. I DO have a problem converting the last one, because the decimal mark is the same character as the thousands separator.
How should I deal with this problem? Is there an explicit conversion string-to-float using a format I can define?
EDIT: I forgot to say, that in the above cases, the last . (if there is any) is always the decimal separator if it is followed by a two digits number. So, '153.650' should convert to 153650 for example.
"EDIT: I forgot to say, that in the above cases, the last . (if there is any) is always the >decimal separator if it is followed by a two digits number. So, '153.650' should convert to >153650 for example."
There's your answer.
Check if the character at index (yourString.Length - 3) is one of your delimiters. If it is, then you have a decimal value; if not, you don't. Proceed to strip out all extraneous symbols and then re-insert your choice of decimal separator at the correct index.
Clean? No. But the situation stinks, TBH.
Correct the data before giving them to SQL - a programming language is simpler, for instance using regular expression replace.
s = s.replaceAll("\\D(\\d\\d\\d)", "$1").replaceFirst("\\D". ".");
(Which does not consider signs!)
It first removes non-digits followed by three digits, and then make a period out of the first remaining non-digit. Can be done smarter.
The above is Java, but regex exists in all sensible programming languages.
you can try this
CONVERT(
REPLACE(REPLACE(value, '.', ''), ',', '.'),
DECIMAL(10,2))
this will replace . and, from your string and will convert it into decimal (10,2).
According To Your
SELECT
IF(
LENGTH(
SUBSTRING_INDEX('351.000', '.', - 1)
) >= "3",
CONVERT(
REPLACE("351.000", ".", ''),
DECIMAL (10, 2)
),
CONVERT(
CONCAT(
REPLACE(
LEFT(
'351.000',
LENGTH("351.000") - LOCATE('.', REVERSE("351.000"))
),
'.',
''
),
CONCAT(
".",
SUBSTRING_INDEX('351.000', '.', - 1)
)
),
DECIMAL (10, 2)
)
)
I have tried for
1234.56 gives 1234.56
1234.000.00 gives 1234000.00
and 1234.000 gives 1234000
but it is not a good way to do so much in mysql query. you should handle it in programming part
SQL Fiddle
MySQL 5.5.32 Schema Setup:
CREATE TABLE Table1
(`TEXT` varchar(10))
;
INSERT INTO Table1
(`TEXT`)
VALUES
('357000'),
('218000.56'),
('500.000.00')
;
Query 1:
SELECT CAST(concat(
REPLACE(CASE WHEN substr(TEXT,-3,1) = "." THEN substr(TEXT,1,length(TEXT)-3)
ELSE TEXT END,'.',''),
CASE WHEN substr(TEXT,-3,1) = "." THEN right(TEXT,3)
ELSE '' END) AS decimal(12,2)
) AS Amount
FROM Table1
Results:
| AMOUNT |
|-----------|
| 357000 |
| 218000.56 |
| 500000 |