MySQL sort data by specific data entries - mysql

I'm not too sure if the title made much sense but I will explain in more detail.
So I have a table named 'members' which has a list of ranks (Col, Maj, Cpt) under the field name 'rank'
I would like to order the data by the rank name going from highest rank (Col) to lowest rank (Rct).
I will include a screenshot of my table just in case I don't make sense.
Table screenshot

I think Alex K.'s solution is the best. You're looking for something like
select * from members order by rank desc; This will return them in descending order alphabetically. If you defined a rank table like Alex suggests you could do a:
select t.*
from members t join rank_table rt on t.rankname = rt.rankname
order by rt.rankvalue desc;
In this solution the rank_table looks like:
Col | 2
Maj | 1
Cap | 0

Related

Is it possible to order by two fields in a given table,one in ascending and the other in descending order at the same time?

Recently, I have come across a question that has been asked in an interview which states that:
You have mysql database with a table students. Write a query string to
select all the items of the table students and order by two fields one
ascending and the other descending.
Let's have a table "students" for example:
From this example, if we order by Score in descending order then there is no way to order by roll_no in ascending order at the same time.
From the point of view of the question, can there be written any query to obtain the desired result Or is the question ambiguous or wrong or my approach to the understanding of the question is wrong?
In your order by you have asked system to order by First column first so it have ordered then you have asked it to order by second column so it have
-> It have to keep ordering of first column.
-> Order by second column too
So it does ordering within group means if
Table Test
A| B
--------
1 1
1 3
1 2
2 2
2 4
Select * from test order by A desc, B asc
Output
Table Test
A| B
--------
2 2
2 4
1 1
1 2
1 3
So in your case, if you first order by score desc then it will order
First, all students according to there scores descending
And then if two or more students have the same score say 60 then within that group the students will be ordered according to roll number ascending
Hope this clears your doubt.
When you use the order by clause, you can specifiy the direction Asc or desc.
In your example with your sample data, there is no point of order by score, then by roll_no, because there is no duplicate in the score column.
If in your real table there are score wich appeared more than once, you can order by score desc, roll_no.
( asc is the default value)

order by lower confidence bound in mysql

I have data in a MySQL database that looks something like this:
name |score
----------
alice|60
mary |55
...
A name can appear many times in the list, but can also appear just once. What I would like is to order the list based on the lower bound of a 95% confidence interval for the name. I tried the following:
SELECT name, count(*) as count_n, stddev_samp(score) as stdv, avg(score) as mean
FROM `my.table`
GROUP BY name
ORDER BY avg(score)-1.96*std(score)/sqrt(count(*)) desc
This produces an output that is ok. Ideally though, I would like to vary the value 1.96, since this should depend on the value of count_n for that name. In fact, it should be a value based on the t-distribution for count_n-1 degrees of freedom. Are there MySQL functions that can do this for me?
I have seen the following answer which looks good but doesn't vary the value as I wold like.
I solved my problem by creating a sepearate table 'tdistribution' with the following structure:
dof | tvalue
------------
1 | -12.706
2 | -4.3026
It contains the degree of freedom and the asscociated t value. Then this table can be joined with the original styled query.
SELECT table2.name,
round(table2.mean-abs(tdistribution.tvalue*table2.stdv/sqrt(table2.nn)),2) AS LCB,
round(table2.mean+abs(tdistribution.tvalue*table2.stdv/sqrt(table2.nn)),2) AS UCB
FROM
(SELECT table1.name, count(table1.name) AS nn, avg(table1.score) AS mean, stddev_samp(table1.score) AS stdv
FROM
(SELECT name, score FROM my.table) AS table1
GROUP BY name
) AS table2
LEFT JOIN tdistribution
ON table2.nn-1=tdistribution.dof
WHERE nn>1
ORDER BY LCB DESC
It seems to work!

select returns wrong id when using max

Assuming a table like this.
id town_id begin_date
12 2 2011-10-10
23 2 2011-11-10
43 2 2012-01-01
now if I do
SELECT id, MAX(begin_date) AS mx
FROM regions
The above query returns the max date but the id is wrong:
id mx
12 2012-01-01
Is this expected?
How can I get it to return the correct id (43, 2012-01-01)
If what you are trying to do is get the id associated with the MAX() date, then you can do:
SELECT id, begin_date from regions order by begin_date DESC LIMIT 1;
You forgot the GROUP BY clause:
SELECT id, MAX(begin_date) AS mx
FROM regions
GROUP BY 1
I also want to add another possible solution to this answer which might be more intuitive because the accepted answer actually is wrong and only the comment below solves it partly. Why? Because it only works if you want a grouped result by town_id. If you you need a solution which retrieves the row with the absolute maximum date you can only go with Francisco Sotos answer or the query below.
SELECT ID, begin_date from regions WHERE begin_date = (SELECT MAX(begin_date) FROM regions)
The query I posted does not use limit but instead requires a sub query. IDK which one is faster but just as an additional food for thought.

Selecting most recent as part of group by (or other solution ...)

I've got a table where the columns that matter look like this:
username
source
description
My goal is to get the 10 most recent records where a user/source combination is unique. From the following data:
1 katie facebook loved it!
2 katie facebook it could have been better.
3 tom twitter less then 140
4 katie twitter Wowzers!
The query should return records 2,3 and 4 (assume higher IDs are more recent - the actual table uses a timestamp column).
My current solution 'works' but requires 1 select to generate the 10 records, then 1 select to get the proper description per row (so 11 selects to generate 10 records) ... I have to imagine there's a better way to go. That solution is:
SELECT max(id) as MAX_ID, username, source, topic
FROM events
GROUP BY source, username
ORDER BY MAX_ID desc;
It returns the proper ids, but the wrong descriptions so I can then select the proper descriptions by the record ID.
Untested, but you should be able to handle this with a join:
SELECT
fullEvent.id,
fullEvent.username,
fullEvent.source,
fullEvent.topic
FROM
events fullEvent JOIN
(
SELECT max(id) as MAX_ID, username, source
FROM events
GROUP BY source, username
) maxEvent ON maxEvent.MAX_ID = fullEvent.id
ORDER BY fullEvent.id desc;

Returning query results in predefined order

Is it possible to do a SELECT statement with a predetermined order, ie. selecting IDs 7,2,5,9 and 8 and returning them in that order, based on nothing more than the ID field?
Both these statements return them in the same order:
SELECT id FROM table WHERE id in (7,2,5,9,8)
SELECT id FROM table WHERE id in (8,2,5,9,7)
I didn't think this was possible, but found a blog entry here that seems to do the type of thing you're after:
SELECT id FROM table WHERE id in (7,2,5,9,8)
ORDER BY FIND_IN_SET(id,"7,2,5,9,8");
will give different results to
SELECT id FROM table WHERE id in (7,2,5,9,8)
ORDER BY FIND_IN_SET(id,"8,2,5,9,7");
FIND_IN_SET returns the position of id in the second argument given to it, so for the first case above, id of 7 is at position 1 in the set, 2 at 2 and so on - mysql internally works out something like
id | FIND_IN_SET
---|-----------
7 | 1
2 | 2
5 | 3
then orders by the results of FIND_IN_SET.
Your best bet is:
ORDER BY FIELD(ID,7,2,4,5,8)
...but it's still ugly.
Could you include a case expression that maps your IDs 7,2,5,... to the ordinals 1,2,3,... and then order by that expression?
All ordering is done by the ORDER BY keywords, you can only however sort ascending and descending. If you are using a language such as PHP you can then sort them accordingly using some code but I do not believe it is possible with MySQL alone.
This works in Oracle. Can you do something similar in MySql?
SELECT ID_FIELD
FROM SOME_TABLE
WHERE ID_FIELD IN(11,10,14,12,13)
ORDER BY
CASE WHEN ID_FIELD = 11 THEN 0
WHEN ID_FIELD = 10 THEN 1
WHEN ID_FIELD = 14 THEN 2
WHEN ID_FIELD = 12 THEN 3
WHEN ID_FIELD = 13 THEN 4
END
You may need to create a temp table with an autonumber field and insert into it in the desired order. Then sort on the new autonumber field.
Erm, not really. Closest you can get is probably:
SELECT * FROM table WHERE id IN (3, 2, 1, 4) ORDER BY id=4, id=1, id=2, id=3
But you probably don't want that :)
It's hard to give you any more specific advice without more information about what's in the tables.
It's hacky (and probably slow), but you can get the effect with UNION ALL:
SELECT id FROM table WHERE id = 7
UNION ALL SELECT id FROM table WHERE id = 2
UNION ALL SELECT id FROM table WHERE id = 5
UNION ALL SELECT id FROM table WHERE id = 9
UNION ALL SELECT id FROM table WHERE id = 8;
Edit: Other people mentioned the find_in_set function which is documented here.
You get answers fast around here, don't you…
The reason I'm asking this is that it's the only way I can think of to avoid sorting a complex multidimensional array. I'm not saying it would be difficult to sort, but if there were a simpler way to do it with straight sql, then why not.
One Oracle solution is:
SELECT id FROM table WHERE id in (7,2,5,9,8)
ORDER BY DECODE(id,7,1,2,2,5,3,9,4,8,5,6);
This assigns an order number to each ID. Works OK for a small set of values.
Best I can think of is adding a second Column orderColumn:
7 1
2 2
5 3
9 4
8 5
And then just do a ORDER BY orderColumn