Order by numeric values in SQL ascending - php

I'm trying to get this output.
MDT 1
MDT 2
MDT 3
MDT 11
MDT 44
but, The values are ordered alphabetically, so 123 comes before 2.
example :
MDT 1
MDT 11
MDT 156
MDT 2
MDT 3
MDT 303
MDT 44
and so on.
I'm use this code, but it seem didn't work.
SELECT * FROM file ORDER BY ABS(ID) ASC
How can I solve this?

If your ID is always going to contain the prefix as MDT, then you can use this, to sort as per your requirement:
SELECT * FROM File
ORDER BY CAST(replace(ID, 'MDT ', '') AS UNSIGNED) ASC
SQLFiddle demo

Try that snippet
SELECT * FROM file ORDER BY ID + 0 ASC

Try Like this it will sort based on numeric :
select substr(id,4)*1 from file order by substr(id,4)*1
It will gives
1
2
3
11
44
...
If You want all fields try the below query ("substr(id,4)" or "substr(id,5)") based on your string length (ex: id= proj-001911 --> take SUBSTR( id, 6 ) *1) )
select * from file order by substr(id,4)*1

SELECT * FROM file
ORDER BY CONVERT(SUBSTRING(ID,5),UNSIGNED) ASC
SUBSTRING() will extract all characters after 'MDT ' and CONVERT() will change remaining substring to unsigned integer on which ORDER BY is performed
note SUBSTR() is a synonym for SUBSTRING().

I was searching it out too, but just while reading over here I got it striked in my head and found one solution that if that column is having only numbers as data then you need to make modification in database table and define that column as INT value type, then I am sure what you need will be done.
Eg. {SELECT * FROM file ORDER BY CONVERT(SUBSTRING(ID,5),UNSIGNED) ASC} in such case Convert is column and that needs to be defined as INT(5) will work.

Related

mySQL - FIND_IN_SET() doesn't find the value

I m trying to get posts which includes a spesific tag.
The tag row content
,iphone|1468338028,,android|1468338028,,blackberry|1468338028,
query
SELECT * FROM shares WHERE FIND_IN_SET(tag, 'iphone') > 0 ORDER BY DATE DESC limit 10
What is the correct way to do it ?
Your tag is iphone|1468338028 and you look for iphone. That does not match.
Replace the | with , to separate the values.
SELECT * FROM shares
WHERE FIND_IN_SET(replace(tag, '|', ','), 'iphone') > 0
Another alternative is to use LIKE "%text%", if you're not required to use FIND_IN_SET().
SELECT * FROM shares
WHERE tag LIKE "%iphone%"
ORDER BY DATE DESC limit 10
Above snippet should achieve the same, thus avoiding replacing and trimming issues.

Highlighting MySQL Data Results

I'm going to struggle to explain this.. so please feel free to ask for more information.
I'm reading data from a MySQL DB Using :
SELECT * FROM resource where date > DATE_SUB(now(), INTERVAL 12 MONTH) ORDER BY `date` DESC
This produces results like this :
ID DATE STACK REF NAME LOCATION CREW
9 2016-01-01 06:34:50 A6YH75F 12 Local List SPAIN 1A
8 2016-01-01 06:34:48 QWE343 23 POINT ONE GERMANY 3A
7 2016-01-01 06:34:46 WER342 43 Insite UK 4A
6 2016-01-01 06:34:44 WFF5G1 34 LANWise FRANCE 5A
5 2016-01-01 06:34:42 2D3D35 21 Polent USA 7A
4 2016-01-01 06:34:40 8541FW 33 Rosta UK 4B
3 2015-12-30 16:48:23 A6YH75F 12 Local List SPAIN 2A
2 2015-11-21 14:32:01 FFCWF4 34 LANWISE FRANCE 6A
1 2015-10-14 11:02:22 POI8H6 75 BALAND IRELAND 6B
This is where it's hard to explain.
I'm looping through the results and echoing out the results into a <table>
When this is live there may appear hundreds of entries for each NAME, what I want to do it highlight output based on some specific criteria.
For example:
If a NAME appears multiple times, compare the latest and previous values of STACK & REF for that name. (so comparing the last two entries per name)
If they are different highlight the output for that entry.
ie:
I can see Local List appears twice in the list. The first date stamp is 2016-01-01 06:34:50 & then at 2015-12-30 16:48:23
Thats fine. On both occasions the STACK and REF are the same.
However LANWISE also appears twice but it's STACK is different on the newer occasion. How do I flag this and highlight the LATEST Entry for LANWISE.
I'm also looking to see if an entry hasn't appeared in the last 65 days.
So looking at the list BALAND last appeared 2015-10-14 11:02:22 so this is greater than 65 days and they haven't appeared since. How do I highlight this ?
Thanks
You can use the following query that returns all of the information required in order to determine records that need to be highlighted:
SELECT ID, `DATE`, STACK, REF, NAME, LOCATION, CREW,
--Calculate difference between `DATE` field and current date
DATEDIFF(NOW(), `DATE`) AS DaysDiff,
-- Get the count of newer records having the same NAME
COALESCE((SELECT COUNT(*)
FROM resource AS r2
WHERE r2.NAME = r1.NAME AND r2.`Date` > r1.`Date`), 0) CountNewer,
-- Find wether an older record exists having the same NAME and
-- different REF or STACK or both
COALESCE((SELECT 1
FROM resource AS r3
WHERE r3.NAME = r1.NAME AND
r3.`Date` < r1.`Date` AND
(r3.REF <> r1.REF OR r3.STACK <> r1.STACK)), 0) IsHighlighted
FROM resource AS r1
WHERE date > DATE_SUB(now(), INTERVAL 12 MONTH)
ORDER BY `date` DESC
I don't know if it's the best way, but I do something like that ($variable is the result of your query)
$already = array();
#The loop where you make your table. I use foreach but use your current loop (probably while if you fetch a query response) :
foreach ($variable as $key => $value) {
$class='';
if(isset($already[$value['name']]) && $already[$value['name']] == $value['date']) {
$class='highlight';
}
#The next time, the variable exist :
$already[$value['name']] = $value['date'];
#do your stuf and add $class to your class in your HTML (and do something inyour CSS)
}
With the isset($already[$value['name']]) you know if the line existing before. And with the == comparator, you know if it's the same value.
Use CSS and class HTML attribute for Highlighting the concerned lines.
Adapt this code for your usage, it's just an example based of your post.
For compare date, you can use DateTime. Example of use :
$datetime1 = new DateTime($xDateDebut[2].'-'.$xDateDebut[1].'-'.$xDateDebut[0]);
$datetime3 = new DateTime(date('Y').'-'.date('m').'-'.date('d'));
$delaisAvantJourJ = $datetime1->diff($datetime3);
($xDateDebut is an explosed SQL date field)
$delaisAvantJourJ is now an object with a lot of usefull information (like the number of day diff)

Numeric value inside varchar MySQL in temporary table

Problem
I have a field with values like
"ABC1234"
"ABC5678/DEF"
"AB1298"
"AB1298/DEF"
I want to extract the numeric value from each one of it, such as:
1234
5678
1298
1298
NOTE: The numeric value is always "together" (1234) and is always composed by 4 digits only.
I was trying to delete first the double quotes to use RegEx: SELECT REPLACE(model_name,'''','') FROM ProductList Note: I replace using ' single quote instead of double quotes " , because that's the way the data was saved, and it works. And then I tried to use Patindex to get the numeric value: SELECT SUBSTRING(field, PATINDEX('%[0-9]%', field), LEN(field)) NOTE: However, PATINDEX does not work with MySQL
I'm trying to do this, because then I want to separate each value in two different columns by creating a temporary table:
SELECT SUBSTR(t.column_one, 1, INSTR(t.column_one, ' ')-1) AS col_one, SUBSTR(t.column_one, INSTR(t.column_one, ' ')+1) AS col_two FROM YOUR_TABLE t
val1 val2
12 34
56 78
12 98
Note: I'm using PHPMyAdmin within XAMPP.
After PATINDEX, I tried LOCATION, and POSITION. (You can see the sequence of the test print screen here ) SELECT SUBSTRING(model_name,LOCATE('%[^0-9]%',model_name),4) FROM ProductList NOTE: The LOCATE or POSITION function is returning a position 0, and that's why there is no result. I can imagine the problem is in "%[^0-9]%", because not LOCATE, POSITION nor MID accept RegEx.
My next problem is: I want to have the lval and rval inside the temporary table footprint, created at the beginning of the query. This, because I would like to create queries by getting input texts values, and have something like:
SELECT * FROM footprint WHERE lval=50;
model_name num_pos lval rval
''ABC1234'' 7 12 34
''ABC1234/DEF'' 7 50 78
''ABDCE1234'' 8 12 98
Solution Proposal
At the end, I want to search the name_model, depending on the values of lval and rval. So the next "query" works for me:
CREATE TEMPORARY TABLE IF NOT EXISTS footprint AS
(SELECT model_name,
LEAST (
if (Locate('0',model_name) >0,Locate('0',model_name),999),
if (Locate('1',model_name) >0,Locate('1',model_name),999),
if (Locate('2',model_name) >0,Locate('2',model_name),999),
if (Locate('3',model_name) >0,Locate('3',model_name),999),
if (Locate('4',model_name) >0,Locate('4',model_name),999),
if (Locate('5',model_name) >0,Locate('5',model_name),999),
if (Locate('6',model_name) >0,Locate('6',model_name),999),
if (Locate('7',model_name) >0,Locate('7',model_name),999),
if (Locate('8',model_name) >0,Locate('8',model_name),999),
if (Locate('9',model_name) >0,Locate('9',model_name),999)
) AS num_Pos
FROM ProductList) ;
SELECT name FROM (SELECT name, left(val,2) AS lval, right(val,2) AS rval FROM
(SELECT MID(pl.model_name, fp.num_Pos,4) AS val, pl.model_name AS name FROM ProductList AS pl INNER JOIN footprint AS fp ON fp.model_name=pl.model_name) p) n WHERE lval='50' and rval='50'
If you have any other suggestion about how this process could be done or improved, please let me know.
Thank you,
Best regards.
To split the numeric and the string part of your values you can use trim, like this:
SELECT trim(field, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ"') AS col0, trim(field, '1234567890"') AS col1 FROM table
Hope it help.
P.S.
This solution also work on sqlite database where the function PATINDEX doesn't exisit.
a double quote is a distinct character not simply 2 single quotes so to strip off the double quotes try.
SELECT REPLACE(model_name,'"','') FROM ProductList
you are sooo close with the code above. given that your numeric portion will always be 4 chars you could use something like this
declare #t as table(field varchar(15))
insert into #t
values
('"ABC1234"'),
('"ABC5678/DEF"'),
('"AB1298"'),
('"AB1298/DEF"')
select left(val,2) as lval, right(val,2) as rval
from
(select SUBSTRING(field, PATINDEX('%[0-9]%', field), 4) val
from #t) t
so with the context of your database it would be something like
select left(val,2) as lval, right(val,2) as rval
from
(select SUBSTRING(model_name, POSITION('%[0-9]%', model_name), 4) val
from ProductList) p
According to all the description I wrote, the next code ended working for me.
A lot of hints are hiding in the description, but if you have any suggestion about the query, be my guest.
CREATE TEMPORARY TABLE IF NOT EXISTS footprint AS
(SELECT model_name,
LEAST (
if (Locate('0',model_name) >0,Locate('0',model_name),999),
if (Locate('1',model_name) >0,Locate('1',model_name),999),
if (Locate('2',model_name) >0,Locate('2',model_name),999),
if (Locate('3',model_name) >0,Locate('3',model_name),999),
if (Locate('4',model_name) >0,Locate('4',model_name),999),
if (Locate('5',model_name) >0,Locate('5',model_name),999),
if (Locate('6',model_name) >0,Locate('6',model_name),999),
if (Locate('7',model_name) >0,Locate('7',model_name),999),
if (Locate('8',model_name) >0,Locate('8',model_name),999),
if (Locate('9',model_name) >0,Locate('9',model_name),999)
) AS num_Pos
FROM ProductList) ;
SELECT name FROM (SELECT name, left(val,2) AS lval, right(val,2) AS rval FROM
(SELECT MID(pl.model_name, fp.num_Pos,4) AS val, pl.model_name AS name FROM ProductList AS pl INNER JOIN footprint AS fp ON fp.model_name=pl.model_name) p) n WHERE lval='50' and rval='50'

Mysql how to select value front of decimal

I'am a newbie.. I'm sorry if my question is repost.. i want to ask how to get value front of decimal on mysql..
here my fiddle example
i try to use FORMAT on mysql
`SELECT FORMAT(desc,0) FROM table1`
the result is round.. in my case i dont want the result rounded.
i want the result is
1. 9
2. 9
3. 11
4. 11
sorry if i'm wrong.. thanks for help..
FLOOR it.
SELECT id, FLOOR(desc) FROM table1
This will remove the decimal places and return that whole number which you are looking for.
Result
9
9
11
11
Fiddle
You can Use FLOOR()
select id,FLOOR(decs) from table1
SQL FIDDLE
SEE HERE
you can also use ROUND to truncate decimal places
SELECT ROUND(#column_name,0,1)
OR
example select CAST(Round(MySum * 20.0 /100, 0) AS INT)
91 * 20 / 100 => 1820 / 100 => 18 (truncated from 18.20)
use round().. get all the data from your sql database then loop it
for example you have
$number = "1.00";
or
$number = 1.00;
then use round()
echo round($number);
the output is 1

mysql between question

For the mysql "between" operator, is it necessary for the before and after value to be numerically in order?
like:
BETWEEN -10 AND 10
BETWEEN 10 AND -10
Will both of these work or just the first one?
Also, can I do:
WHERE thing<10 AND thing>-10
Will that work or do I have to use between?
Lastly, can I do:
WHERE -10<thing<10
?
BETWEEN -10 AND 10
This will match any value from -10 to 10, bounds included.
BETWEEN 10 AND -10
This will never match anything.
WHERE thing<10 AND thing>-10
This will match any value from -10 to 10, bounds excluded.
Also, if thing is a non-deterministic expression, it is evaluated once in case of BETWEEN and twice in case of double inequality:
SELECT COUNT(*)
FROM million_records
WHERE RAND() BETWEEN 0.6 AND 0.8;
will return a value around 200,000;
SELECT COUNT(*)
FROM million_records
WHERE RAND() >= 0.6 AND RAND() <= 0.8;
will return a value around 320,000
The min value must come before the max value. Also note that the end points are included, so BETWEEN is equivalent to:
WHERE thing>=-10 AND thing<=10
Please keep it to one question per post. Anyway:
http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#operator_between
BETWEEN min AND max, in that order.
from the link:
This is equivalent to the expression (min <= expr AND expr <= max) if
all the arguments are of the same type
The second alternative will also work, of course.
First question:
Will both of these work or just the first one?
yes,both of these work
Second question:
Will that work or do I have to use between?
it also valid but as you can see just empty result
Yes your between must be in order to return the excepted result.
Let's say you have a table with a row called mynumber that contains 10 rows :
MyNumber
--------
1
2
3
4
5
6
7
8
9
10
So
select * from thistable table where table.myNumber BETWEEN 1 and 5
will return
1
2
3
4
5
but
select * from thistable table where table.myNumber BETWEEN 5 and 1
return nothing.
Your 2nd question : yes it is the same thing. but beware in you example you will have to put <= and >= to be the same as between. if not, in our example, you would get
2
3
4
Hope it help
I've already seen such things work with integers :
WHERE -10
But it's better to avoid it. One reason is that it doesn't seem to work well with other types. And MySQL doesn't issue any warning.
I've tried it with datetime columns, and the result was wrong.
My request looked like this one:
SELECT *
FROM FACT__MODULATION_CONSTRAINTS constraints
WHERE constraints.START_VALIDITY<= now() < constraints.END_VALIDITY
The result was not as expected. I got twice as many results as the same request with two inequalities (which returned correct results). Only the 1st part of the expression evaluated correctly.

Categories