Order Selected SQL result by the Numbers - mysql

I Have a Table which has a Column of Type 'varchar' of size 255 char. The sample values look like this
Test/16-17/1
Test/16-17/2
test/16-17/10
Test/16-17/11
Test/16-17/20
Test/16-17/22
However on Using ORDER BY clause in the Select the Result is in following order
Test/16-17/1
Test/16-17/10
Test/16-17/11
Test/16-17/2
Test/16-17/20
Test/16-17/22
How Do I get the Result in the Chronolgical Order of Numerical Values in the End of the values?

If it follows the same / and have 2 digits in the column, you can use
order by right(vtest,2)

ORDER BY CONVERT( RIGHT( test_column_name,
LENGTH(test_column_name) - LOCATE('/', REVERSE(test_column_name))
), UNSIGNED INTEGER);
OR
ORDER BY CONVERT(substring_index(id, '/', -1), UNSIGNED INTEGER);

For your particular examples, you can order by length and then the value:
order by length(vtest), vtest
I don't know if this will work for other rows not in the question.

This will work no matter what the first 10 characters are:
ORDER BY CONCAT(LEFT(vtest, 10), CASE WHEN LENGTH(vtest) = 12
THEN CONCAT(0,RIGHT(vtest,1))
ELSE RIGHT(vtest,2) END)

Select the end part after the last "/", and then multiply it by 1 to convert it to a number:
ORDER BY RIGHT(test_column, LENGTH(test_column) - LOCATE('/', REVERSE(test_column))) * 1;
OR
ORDER BY substring_index(id, '/', -1) * 1;
This is basically the same as the answer by Keyur Panchal, but it uses implicit conversion which has several advantages: 1) Easier to read/write, 2) You don't need to worry about the type to convert to, 3) It ignores characters if they happen to exist in some values.

Related

SQL ORDER BY date DESC

I have a table with several rows of timestamp (unix epoch)
eg: 1620518277 , 1556748676 , 1547547076, 1602756807, 944971077 (field name -> date_stamp)
And by using
SELECT *
FROM table
ORDER BY date_stamp DESC
The result of this query is :
1. 944971077
2. 1620518277
3. 1602756807
4. 1556748676
5. 1547547076
Everything is sorted fine but how can 944971077 > 1620518277 ???
Anybody had this kind of strange SQL issues ?
Presumably, you are storing these timestamps as strings, not as numbers. A simple option forces a numeric conversion:
SELECT * FROM table ORDER BY date_stamp + 0 DESC
This would occur if timestamp were a string. A simple method is to convert to a number using implicit conversion:
SELECT *
FROM table
ORDER BY date_stamp + 0 DESC

How to use SQL to sort a column by the first group of digits that appears in each row?

Is there a way to use SQL to sort a column by the first group of digits that appears in the column?
For example, the column contains values like so:
PPP-26-8
PPP-29-8
PPP-216-8
PPP-220
PPP-236
Only the first group of digits is to be considered for sorting in increasing numerical order, i.e. 26, 29, 216, 220, 236
I currently have something like this, which kind of works, but gives me warnings:
CAST(RIGHT(model, LENGTH(model) - 4) as UNSIGNED) ASC
Warning, specifically is this:
Warning | 1292 | Truncated incorrect INTEGER value: '216-8'
Update
It seems like this will do it, where - is the delimiter:
CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(model, '-', 2), '-', -1) as UNSIGNED) ASC
You could use string function to get string after first - and * 1 for type casting
select *
from demo
order by substring_index(substring_index(col,'-',2),'-',-1) * 1
demo
Assuming you always mean the second group (as defined by the "-"), then you can use substring_index(). If they always begin with "P-", you can do:
order by length(substring_index(model, '-', 2)),
substring_index(model, '-', 2)
If the initial part can be of variable length, go fo:
order by substring_index(substring_index(model, '-', 2), '-', -1) + 0
The + 0 converts the value to a number, for ordering purposes. The use + 0 for conversion uses silent conversion in MySQL. That is, it does not generate an error when the string is non-numeric. Instead, it just treats such strings as a value of "0".
You can try this:
SELECT ...
FROM MyTable
ORDER BY SUBSTRING_INDEX(SUBSTRING_INDEX(model, '-', 2), '-', -1);
If you want this to use an index, you'll have to create a virtual column and an index on the virtual column (this works in MySQL 5.7 and later).
ALTER TABLE MyTable
ADD COLUMN model_second_number AS (SUBSTRING_INDEX(SUBSTRING_INDEX(model, '-', 2), '-', -1)+0),
ADD KEY (model_second_number);
Then you have an opportunity to sort by that index:
SELECT ...
FROM MyTable
ORDER BY model_second_number;

How to compare current date with a date range or discrete date values in MySQL?

I am saving multiple dates in database in one column separates by comma(,) like
2017-03-05, 2017-03-06, 2017-03-07, 2017-03-08, 2017-03-08.
2017-03-05, 2017-03-08
I just want to know that how I compare current date by these dates. In the first example, its easy, but problem is for the second one.
Can anyone help me out....?
Thanks...
As others have commented, it would be preferable to normalise the data and store individual dates in multiple rows of a linked table rather than in a single field. But assuming there's a valid reason this can't be done, the following will do what you've asked:
SELECT date_csv,
CASE WHEN CHAR_LENGTH(REPLACE(date_csv, ',', '')) = CHAR_LENGTH(date_csv) - 1
THEN /* date_csv has a single comma */
CURRENT_DATE >= SUBSTRING(date_csv, 1, INSTR(date_csv, ',') - 1)
AND CURRENT_DATE <= SUBSTRING(date_csv, INSTR(date_csv, ',') + 1)
ELSE /* date_csv has either no comma or multiple commas */
FIND_IN_SET(DATE_FORMAT(CURRENT_DATE,'%Y-%m-%d'), date_csv) > 0
END AS 'Test result'
Rextester demo: http://rextester.com/EPKO65812
Use FIND_IN_SET
SELECT * FROM your_table
WHERE FIND_IN_SET('2017-03-08',comma_date );
you can use FIND_IN_SET to compare CURRENT_DATE with your comma separated
dates
SELECT FIND_IN_SET(CURRENT_DATE,'2017-03-05,2017-03-06,2017-03-07,2017-03-08,2017-03-08');
EDIT
MySQL FIND_IN_SET() returns the position of a string if it is present (as a substring) within a list of strings, so for your second set it simple returns zero
so you can do some thing like below
SELECT * from tbl where FIND_IN_SET(CURRENT_DATE,'2017-03-05,2017-03-08')>0
I would definitely use find_in_set() and substring_index(), if I had such a lousy data structure:
select t.*
from t
where find_in_set(date_format(curdate(), '%Y-%m-%d'), datecol) > 0 or
(datecol like '%,%' and datecol not like '%,%,%' and
date_format(curdate(), '%Y-%m-%d') between substring_index(datecol, ',', 1) and substring_index(datecol, ',', -1)
);
<?php
$string_date='2017-03-05,2017-03-06,2017-03-07,2017-03-08,2017-03-08';
$tmp_dates=explode(',',$string_date);
foreach($tmp_dates as $tmp_date)
{
$newDateString = date_format(date_create_from_format('Y-m-d', $tmp_date), 'Y-m-d');
$interval =date_diff(date_create($newDateString),date_create(date('Y-m-d')));
echo $interval->format('%R%a days');
echo '<br>';
}
?>

MySQL Executing string as math operation

In a column I have something like this:
Amount:
12
2x25
192
How is it possible to multiply in this example 2x25 to order it correctly ASC.
My starting point:
SELECT * FROM table
ORDER BY REPLACE(Amount,'x','*') ASC
TIA
frgtv10
try this
SELECT
CAST(if(Amount LIKE '%x%', SUBSTRING_INDEX(Amount, 'x', 1) *
SUBSTRING_INDEX(Amount, 'x', -1) , Amount) as unsigned ) as amount
FROM table1
ORDER BY Amount ASC
DEMO HERE
steps and explaining :
locate fields with x value
sbstring from left and right and multiply it.
then cast the multiplication as unsigned.
order it asc
As long as this is the only formula (multiplying 2 numbers), you should be able to hard-code it with INSTR, SUBSTRING, and CONVERT.

MySQL: how to get average of positive values only?

Suppose I have INT column, and I am using -1 to signify that no data was available at the time of the INSERT. I'd like to get an AVG of all values of this column that are 0 or larger.
Is this possible?
Thanks.
I forgot to mention that I'm doing this alongside other AVG's, so it's select avg(a), avg(b), avg(d) from tab; ... so I can't use b>0... because the others need to use the row data regardless of this one column's data being -1.
It occurs to me though that I could augment the AVG result e.g. if it would normally be (4 + 5 + -1 + -1 + 6) / 5. But if I know how many -1's there are I could "fix" the result to exclude them.
This might help:
If you want to ignore the -1 values from the average:
SELECT AVG(`a`), AVG(IF(`b` > -1, `b`, NULL)), AVG(`c`) FROM `t`;
If you want to consider the -1 values in the average:
SELECT AVG(`a`), AVG(IF(`b` > -1, `b`, 0)), AVG(`c`) FROM `t`;
I've assumed dummy column- and table- names and assumed column b as the one for which you want to consider only values >= 0. Please feel free to put in names as per your schema.
SELECT AVG(`field`) FROM `table` WHERE `field` >= 0
Please use this:
SELECT AVG(Column),
SUM(IF(Column>0))/COUNT(IF(Column>0))
FROM Table
Could you do something as such
SUM(column) / COUNT(*) as Average FROM 'table' WHERE 'column' >= 0