SQL sort by number in column - mysql

id| name | created_at
—-----------------------------
1 | name 1 | 2017-05-20
2 | name 2 | 2017-05-22
3 | name 66 | 2017-05-24
4 | name 44 | 2017-05-25
i have a table Orders
I have to sort it by number in name column
like
id| name | created_at
—-----------------------------
1 | name 66 | 2017-05-20
2 | name 44 | 2017-05-22
3 | name 2 | 2017-05-24
4 | name 1 | 2017-05-25
I have tried SELECT * FROM Orders ORDER BY name DESC; but no luck;
how i can do it?

If all the names are in the format name, space, number you can use this query. The SUBSTRING_INDEX extracts the characters from the last space to the end and they are then CAST as an unsigned integer, which allows them to be sorted.
SELECT *
FROM Orders
ORDER BY CAST(SUBSTRING_INDEX(name, ' ', -1) AS UNSIGNED) DESC
Output:
id name created_at
3 name 66 2017-05-24
4 name 44 2017-05-25
2 name 2 2017-05-22
1 name 1 2017-05-20

There is a simple trick to do this, that is to order by length first, then by name. Example:
SELECT *
FROM Orders
ORDER BY LENGTH(name) DESC, name DESC
Here's an example of this in action: SQL Fiddle
Edit: Please note, his will only work if your string is consistent as it is in your example data.

Following query extracts number in name column with substring function and then order it accordingly.
SELECT *
FROM Orders
ORDER BY CAST(SUBSTRING(name, length('name')+2 , 3) AS UNSIGNED) DESC

If 'name' is not the same on each row, then you can do:
order by substring_index(name, ' ', 1),
substring_index(name, ' ', -1) + 0
This will work if you have values such as:
a 1
a 2
a 10
b 1
b 100
(and of course if all start with "name" as well)

Related

How to get maximum appearance count of number from comma separated number string from multiple rows in MySQL?

My MySQL table having column with comma separated numbers. See below example -
| style_ids |
| ---------- |
| 5,3,10,2,7 |
| 1,5,12,9 |
| 6,3,5,9,4 |
| 8,3,5,7,12 |
| 7,4,9,3,5 |
So my expected result should have top 5 numbers with maximum appearance count in descending order as 5 rows as below -
| number | appearance_count_in_all_rows |
| -------|----------------------------- |
| 5 | 5 |
| 3 | 4 |
| 9 | 3 |
| 7 | 2 |
| 4 | 2 |
Is it possible to get above result by MySQL query ?
As already alluded to in the comments, this is a really bad idea. But here is one way of doing it -
WITH RECURSIVE seq (n) AS (
SELECT 1 UNION ALL SELECT n+1 FROM seq WHERE n < 20
), tbl (style_ids) AS (
SELECT '5,3,10,2,7' UNION ALL
SELECT '1,5,12,9' UNION ALL
SELECT '6,3,5,9,4' UNION ALL
SELECT '8,3,5,7,12' UNION ALL
SELECT '7,4,9,3,5'
)
SELECT seq.n, COUNT(*) appearance_count_in_all_rows
FROM seq
JOIN tbl ON FIND_IN_SET(seq.n, tbl.style_ids)
GROUP BY seq.n
ORDER BY appearance_count_in_all_rows DESC
LIMIT 5;
Just replace the tbl cte with your table.
As already pointed out you should fix the data if possible.
For further details read Is storing a delimited list in a database column really that bad?.
You could use below answer which is well explained here and a working fiddle can be found here.
Try,
select distinct_nr,count(distinct_nr) as appearance_count_in_all_rows
from ( select substring_index(substring_index(style_ids, ',', n), ',', -1) as distinct_nr
from test
join numbers on char_length(style_ids) - char_length(replace(style_ids, ',', '')) >= n - 1
) x
group by distinct_nr
order by appearance_count_in_all_rows desc ;

how to sort results by specific values in mysql

We have a DB called transaction. It has user_id, date, value and so on. I use pagination in my query also. I have thousands of record in my table which has user_id equal to 2 or other value. put the user_id = 2 at the very last page.
I want to sort the result like this:
sort the results by date but if the user_id= 2 , put all results associated with the user_id= 2 at the end.
to be more clear, I show you what I want in the below.
-------------------------------------
| ID | user_id | date | ......
-------------------------------------
| 1 | 10 | 2018-10-20 |
-------------------------------------
| 2 | 11 | 2018-10-21 |
-------------------------------------
| 3 | 2 | 2018-10-22 |
-------------------------------------
| 4 | 2 | 2018-10-23 |
the results have to be like this:
first: ID = 2, second: ID = 1, third: ID = 4, last: ID = 3
tip *:
I use field function but unfortunately in vain.
ORDER BY FIELD(user_id, 2) DESC, date DESC
You may try using a CASE expression in your ORDER BY clause:
SELECT *
FROM yourTable
ORDER BY
CASE WHEN user_id = 2 THEN 1 ELSE 0 END,
date DESC;
I'm not sure if you want each group sorted by date ascending or descending. If you want ascending date order, then remove the DESC keyword at the end of my query.

Mysql - Concat fields based on value of field

Given a table like this:
id name field
1 walt a
2 hurley b
3 jack c
4 kate a
5 sawyer a
6 john a
7 ben b
8 miles null
9 juliet c
10 jacob d
11 richard null
How would you transfer it into this:
id ids names field
1 1,4,5,6 walt, kate, sawyer, john a
2 2,7 hurley, ben b
3 8 miles null
4 3,9 jack, juliet c
5 10 jacob d
6 11 richard null
It needs to look at all the rows having the same field value. Then it needs to "merge" all other values based on equality of the field value. However if the field value is null, it should do nothing.
I got this to work:
mysql> set #x:= 1;
mysql> select group_concat(id) as ids, group_concat(name) as names, field
from `a table like this` group by coalesce(field, #x:=#x+1);
+---------+-----------------------+-------+
| ids | names | field |
+---------+-----------------------+-------+
| 8 | miles | NULL |
| 11 | richard | NULL |
| 1,4,5,6 | walt,kate,sawyer,john | a |
| 2,7 | hurley,ben | b |
| 3,9 | jack,juliet | c |
| 10 | jacob | d |
+---------+-----------------------+-------+
Basically, I tricked the query into treating each NULL as a non-NULL value that increments each time we evaluate it, so each row with a NULL counts as a distinct group.
Re your comment:
You can also initialize a variable within the query like this:
select group_concat(id) as ids, group_concat(name) as names, field
from (select #x:=1) AS _init
cross join `a table like this`
group by coalesce(field, #x:=#x+1);
GROUP_CONCAT can be used to aggregate data from different rows into a concatenated string (as its name would suggest); it also supports and ORDER BY clause of it's own, so you want make doubly sure corresponding values end up in the same relative position of the list*.
SELECT MIN(id)
, GROUP_CONCAT(id ORDER BY id)
, GROUP_CONCAT(name ORDER BY id)
, field
FROM theTable
WHERE field IS NOT NULL
GROUP BY field
UNION
SELECT id, id, name, field
FROM theTable
WHERE field IS NULL
;
* aggregate functions ignore NULL values, so technically if either id or name contain NULL, the lists will become misaligned; this could be remedied with something like GROUP_CONCAT(IFNULL(concatenated_value, '[null]') ORDER BY ordering_value)

SQL - Retrieve Avg Score from Group

My Database contains the following:
| ID | UID | file | score | time |
1 | a827vgj28df | jack_123 | 75 | 12:44
2 | ayeskfkfjhk | jack_999 | 5 | 12:12
3 | b83759 | adam_123 | 7 | 12:12
Goal:
I am trying to get a query that displays the avg scores for each file prefix (jack/adam)
To display like:
| Key | AVG
jack 40
adam 7
You can use substring_index to extract the name prefixes. From there on, it's just a simple use of avg:
SELECT SUBSTRING_INDEX(file, '_', 1) AS key, AVG(score)
FROM mytable
GROUP BY SUBSTRING_INDEX(file, '_', 1)
you can get the key using SUBSTRING_INDEX and then group by
SELECT
SUBSTRING_INDEX(file, '_', 1) AS key
, avg(score) average
from my_table
group by key
Should be something like
select SUBSTRING(file, 1, 4) as Key, AVG(score)
from table
group by SUBSTRING(file, 1, 4)
You might get a better response in the future if you share what you've already tried.

groupby get the average length name

I'm using the group by function to get some products from my little shop like:
select name, ProductID from blog group by ProductID
+----------------------------------------------------------+
| name |
+----------------------------------------------------------+
| AAA |
| BBBB |
| CCCC |
| DDDDDDDD |
+----------------------------------------------------------+
Is it possible to get the average length name in the groupby function?
EDIT (from OP, placed in answer):
myysql> select length(name) as len, name from product where article=40 order by len asc;
+------+----------------------------------------------------------+
| len | name |
+------+----------------------------------------------------------+
| 3 | aaa |
| 6 | BBBBBB |
| 6 | CCCCCC |
| 8 | dddddddd |
+------+----------------------------------------------------------+
4 rows in set (0.00 sec)
by this example I need to get one value like BBBBBB or CCCCCC (AVG?)
Your example doesn't get the average length name, because there is no such thing. The average length would be (8 + 3 + 6 + 6) / 4 = 5.75. It doesn't exist. I think you want the median, which is the size such that 50% are bigger and 50% are smaller.
Here is one way to get the median (assuming that names don't contain commas and that the concatenation doesn't exceed certain limits):
select ProductID,
substring_index(substring_index(group_concat(name order by length(name) separator '||'
), '||', 1 + count(*)/2
), '||', -1) as MedianLengthName
from blog
group by ProductID;
Try this query:
SELECT AVG(CHAR_LENGTH(name)) AS avg FROM tbl;
If you are looking for an the mean average (which implies you would have to accept the integer above and below that decimal value), you can use this:
SELECT *
FROM (
SELECT AVG(CHAR_LENGTH(name)) AS average
FROM product) AS calculated
JOIN product
ON CHAR_LENGTH(name) BETWEEN FLOOR(average) AND CEILING(average);