mysql sort by column with addotinal parameter - mysql

I'm not sou sure if this is possible at all but is worth asking the question.
I would like to sort table by drivers id's
SELECT * FROM test ORDER BY driverid DESC
there is another table 'drivers' with the list of drivers where each driver has corresponding que number:
driver | driverid | queno
-------------------
drv1 | 15 | 3
drv2 | 30 | 1
drv3 | 40 | 2
so from 'test' db I can take driverid. But I would like to sort out this listing not by driverid but by queno. Is there any way to bring queno to the game...

SELECT t.*
FROM test t
LEFT JOIN drivers d ON t.driverid = d.driverid
ORDER BY d.queno DESC

SELECT * FROM test JOIN drivers ON test.driverid=drivers.driverid ORDER BY queno DESC

Related

Is it possible to make this query working properly?

I'm creating a simple game and I want to get the best lap_time for each type in the db.
However, my query returns the wrong player_id (3 in second row) and total_ranks (all ranks instead of count by type).
Link to sqlfiddle: http://sqlfiddle.com/#!9/a0c36a/2
Desired result
+--------+-----+-------+------------+----------------+-------------+
| level | cp | type | player_id | MIN(lap_time) | total_ranks |
+--------+-----+-------+------------+----------------+-------------+
| 1 | 1 | 0 | 1 | 10.5 | 4 |
| 1 | 1 | 1 | 2 | 10.45 | 3 |
+--------+-----+-------+------------+----------------+-------------+
Is it possible to make it work in 1 query or do I need at least 2?
Fiddle
Same concept as Tim, but with Total_Ranks column
SELECT level, cp, R.type, player_id, MinTime, Total_Ranks
FROM runtimes R
JOIN (SELECT TYPE, MIN(LAP_TIME) MinTime, Count(*) Total_Ranks
FROM RUNTIMES
GROUP BY TYPE) T on R.Type = T.Type
and R.lap_time = T.MinTime
WHERE level=1
AND cp=1
One canonical way to solve this problem in MySQL is to use a subquery to identify the minimum lap time for each type. Then join your full table to this to obtain the entire record. Note that a nice side effect of this approach is that we also get back ties if a given type have more than one person sharing the minimum lap time.
SELECT r1.*, r2.total_ranks
FROM runtimes r1
INNER JOIN
(
SELECT type, MIN(lap_time) AS min_lap_time, COUNT(*) AS total_ranks
FROM runtimes
GROUP BY type
) r2
ON r1.type = r2.type AND
r1.lap_time = r2.min_lap_time
Here is a link to your updated Fiddle:
SQLFiddle

Mailbox view like Facebook, with ORDER BY before GROUP BY

i'm looking for a solution for my query, for improving the performances.
I've just read several threads about that but (maybe to cause me) they aren't fitting for my case.
Anyway, here is my issue.
I've a msg table something like:
IDMSG | THREAD | SENDER | RECEIVER | DATE | MSG | READ
1521 | 2 | 20 | 43 | 05/24/2014 | hello guys | 0
1522 | 3 | 84 | 43 | 05/24/2014 | hi man | 0
1523 | 2 | 20 | 43 | 05/24/2014 | yes, of coure | 0
Now, you'll see that the user 20 has written 2 msg to me (43), so, on my msg index page, i'd like to print the latest msg of the thread, and sort it in a just way.
For instance:
05/24/2014 - (Preview text:) Yes of course - by Erick (thread 2)
05/24/2014 - (Preview text:) Hi man. - by Manuel (thread 3)
05/21/2014 - (Preview text:) I'm female - by Sandra.
etc etc.
Currently, my real query is:
SELECT * FROM
(SELECT * FROM boxmsg
LEFT JOIN user ON sender = id WHERE receiver = '959749'
ORDER BY idmsg DESC)
AS temp_tbl
GROUP BY thread ORDER BY idmsg DESC LIMIT 0,20
So, it works right, but the performance is a real disaster.
Indeed, it scans whole database because the indexes in a derivate table have several problem.
How can i get the same result, having latest msg of a thread?
Thank you at all and sorry for my awful english.
This is your query:
SELECT *
FROM (SELECT *
FROM boxmsg LEFT JOIN
user
ON sender = id
WHERE receiver = '959749'
ORDER BY idmsg DESC
) temp_tbl
GROUP BY thread
ORDER BY idmsg DESC
LIMIT 0, 20;
MySQL specifically warns against this use of * with group by (see here).
For what you want to do, try the following query:
SELECT *
FROM boxmsg bm LEFT JOIN
user
ON sender = id
WHERE receiver = '959749' AND
NOT EXISTS (SELECT 1
FROM boxmsg bm2
WHERE bm2.receiver = bm.receiver and
bm2.thread = bm.thread and
bm2.idmsg > bm.idmsg
)
ORDER BY idmsg DESC
LIMIT 0, 20;
Before running the query, create an index on boxmsg(receiver, thread, idmsg) and an index on user(id) (if one doesn't already exist).
Something like:
SELECT b.*
FROM boxmsg b
JOIN (
SELECT thread, MAX(idmsg) as idmsg
FROM boxmsg x
GROUP BY thread
) a
ON a.thread = b.thread
AND a.idmsg = b.idmsg
An index on thread, idmsg will likely help improve performance

Query1 Join with Query2 but Query2 use the result of Query1, How to do that with just 1 query?

Ok, I have a complicated query to get all article details, each article has many versions. I have a need to get details of article with latest version only (ie take the max version). Here is the table:
+------------+-----------+----------+
| ArticleID | Detail | Version |
+------------+-----------+----------+
| 1 | detail1 | 1 |
| 1 | detail2 | 1 |
| 1 | detail3 | 2 |
| 1 | detail4 | 2 |
| 3 | detail3 | 2 |
| 3 | detail6 | 2 |
| 3 | detail4 | 3 |
+------------+-----------+----------+
Now user just provides a detail & the query will take all details of all articles with version=max(version)
Suppose that if we don't care about max version, then a simple query could be
Select * from articleTb where Detail like '%3'
It will print out:
+------------+-----------+----------+
| ArticleID | Detail | Version |
+------------+-----------+----------+
| 1 | detail3 | 2 |
| 3 | detail3 | 2 |
+------------+-----------+----------+
But this doesn't meet the requirement cos the result should not have this record 3 - detail3 - 2 cos it doesn't contain the max version of articleID=3.
Let say user search for Detail like '%4', then a correct query should be:
ArticleID - Detail - Version
+----+-----------+----+
| 1 | detail4 | 2 |
+----+-----------+----+
| 3 | detail4 | 3 |
+----+-----------+----+
The 2 records appear cos they belongs to the article with max version. Explain, 2 is the maxversion of articleID=1 so it matches the condition, & 3 is the max version of articleID=3 so it also matches the condition.
So here is what i did,
select * from (Select * from articleTb where Detail like '%3') tb1
Join (select articleID, max(version) maxversion from articleTb where
Detail like '%3' group by articleID) tb2
on tb1.articleID=tb2.articleID and tb1.version=tb2.maxversion
However, for the above query the system have to duplicate the task where Detail like '%3' which is not good. Besides, my real world query1 is much more complicated than where Detail like '%3', then if i do like the above then the query will implement the same job TWICE? & that is very inefficient.
So how to deal this problem?
To improve performance, remove the unnecessary inline view, e.g.
SELECT tb1.*
FROM articleTb tb1
JOIN ( SELECT b.articleID
, MAX(b.version) AS maxversion
FROM articleTb b
WHERE b.Detail LIKE '%3'
GROUP BY b.articleID
) tb2
ON tb1.articleID = tb2.articleID
AND tb1.version = tb2.maxversion
WHERE tb1.Detail LIKE '%3'
and...
make sure you have appropriate indexes. A covering index with a leading column of article may enable MySQL to use the index to optimize the GROUP BY (avoiding a "Using filesort" operation.)
... ON articleTb (articleID, version, detail)
MySQL may also be able to use that index for the join to tb1; the derived table (inline view) won't have an index.
You can confirm the execution plan with an EXPLAIN.
I would use a CTE to create a table that contains the article id and the version id, then use that in my main query to filter down to the most recent version.
with latest as
(
select articleId, max(version) as version from articleTb
)
select ....
from articleTb a
inner join latestl on a.articleid = l.articleid and l.version = a.version
Use of aggregate table will helpful.
Let me describe a scenario first. Day 1, you get a flat file first time ever.
1. Load that in a staging table.
2. Find ArticleID, MAx (Version) for each Article ID, and store in the aggregate table.
3. Left outer join the stage table with the aggregate table joining on article ID. Pick the higher version. This will lead to your result.
4. Truncate the staging table.
Next day when a new feed arrives, the file will again be loaded into the truncated table, and left joined.
You can add a few audit fields in aggregate table such as date when that file arrived, maybe file name too. I had used this method in one of the projects in a insurance companies that resulted into several fold performance gain.
This is your query:
select *
from (Select * from articleTb where Detail like '%3'
) tb1 Join
(select articleID, max(version) maxversion
from articleTb
where Detail like '%3'
group by articleID
) tb2
on tb1.articleID=tb2.articleID and tb1.version=tb2.maxversion;
You are trying to get the last version of a particular type of article. Another approach is to use not exists:
select *
from articleTb t
where Detail like '%3' and
not exists (select 1
from articleTb t2
where t2.articleID = t1.articleID and
t2.Detail like '%3'
t2.version > t.version
);
This is saying: "Get me all the rows from articleTb where Detail ends in 3 and there isn't another version that is higher".
To improve performance, create an index on: articleTb(articleID, Detail, version). The one question is whether t2.Detail like '%3' is needed for the subquery -- does that condition filter articles or versions within an article? If it is not needed, then remove the index and change the condition to articleTb(articleID, version).

MySQL: How to limit results to max value of another field?

In this scenario, I am trying to report on the operating_system_version for each distinct computer_id where the report_id for that computer_id is the greatest.
Currently, I am getting the below results:
operating_system_version | computer_id | report_id
10.8 | 1 | 10
10.9 | 1 | 20
10.9 | 2 | 11
10.8 | 2 | 21
The above is returned by this statement:
SELECT operating_systems.operating_system_version,
reports.computer_id,
reports.report_id
FROM operating_systems
INNER JOIN reports
ON operating_systems.report_id = reports.computer_id
Instead, would like return the most recent (highest report_id) operating_system_version for each distinct computer_id, for example:
operating_system_version | computer_id | report_id
10.9 | 1 | 20
10.8 | 2 | 21
I am brand new to SQL .. Appreciate any help.
You would need to add a group by statement and a having statement.
The group by would look like
group by computer_id
The having would look like
having report_id= (select max(report_id) )
SELECT operating_systems.operating_system_version,
reports.computer_id,
reports.report_id
FROM operating_systems INNER JOIN reports ON operating_systems.report_id = reports.computer_id
WHERE NOT EXISTS (SELECT 1
FROM reports r2
WHERE r2.computer_id = reports.computer_id
AND r2.reports_id > reports.reports_id)
A subquery would lead you to desired end result:
SELECT os.operating_system_version,
r2.computer_id,
MAX(r2.report_id)
FROM (
SELECT DISTINCT computer_id
FROM reports
) r
INNER JOIN operating_systems os
ON os.report_id = r.computer_id
INNER JOIN reports r2
ON r2.computer_id = r.computer_id
Need to do a better job looking through other posts. This question is answered in an excellent post at: SQL Select only rows with Max Value on a Column

Using ORDER BY and GROUP BY together

My table looks like this (and I'm using MySQL):
m_id | v_id | timestamp
------------------------
6 | 1 | 1333635317
34 | 1 | 1333635323
34 | 1 | 1333635336
6 | 1 | 1333635343
6 | 1 | 1333635349
My target is to take each m_id one time, and order by the highest timestamp.
The result should be:
m_id | v_id | timestamp
------------------------
6 | 1 | 1333635349
34 | 1 | 1333635336
And i wrote this query:
SELECT * FROM table GROUP BY m_id ORDER BY timestamp DESC
But, the results are:
m_id | v_id | timestamp
------------------------
34 | 1 | 1333635323
6 | 1 | 1333635317
I think it causes because it first does GROUP_BY and then ORDER the results.
Any ideas? Thank you.
One way to do this that correctly uses group by:
select l.*
from table l
inner join (
select
m_id, max(timestamp) as latest
from table
group by m_id
) r
on l.timestamp = r.latest and l.m_id = r.m_id
order by timestamp desc
How this works:
selects the latest timestamp for each distinct m_id in the subquery
only selects rows from table that match a row from the subquery (this operation -- where a join is performed, but no columns are selected from the second table, it's just used as a filter -- is known as a "semijoin" in case you were curious)
orders the rows
If you really don't care about which timestamp you'll get and your v_id is always the same for a given m_i you can do the following:
select m_id, v_id, max(timestamp) from table
group by m_id, v_id
order by max(timestamp) desc
Now, if the v_id changes for a given m_id then you should do the following
select t1.* from table t1
left join table t2 on t1.m_id = t2.m_id and t1.timestamp < t2.timestamp
where t2.timestamp is null
order by t1.timestamp desc
Here is the simplest solution
select m_id,v_id,max(timestamp) from table group by m_id;
Group by m_id but get max of timestamp for each m_id.
You can try this
SELECT tbl.* FROM (SELECT * FROM table ORDER BY timestamp DESC) as tbl
GROUP BY tbl.m_id
SQL>
SELECT interview.qtrcode QTR, interview.companyname "Company Name", interview.division Division
FROM interview
JOIN jobsdev.employer
ON (interview.companyname = employer.companyname AND employer.zipcode like '100%')
GROUP BY interview.qtrcode, interview.companyname, interview.division
ORDER BY interview.qtrcode;
I felt confused when I tried to understand the question and answers at first. I spent some time reading and I would like to make a summary.
The OP's example is a little bit misleading.
At first I didn't understand why the accepted answer is the accepted answer.. I thought that the OP's request could be simply fulfilled with
select m_id, v_id, max(timestamp) as max_time from table
group by m_id, v_id
order by max_time desc
Then I took a second look at the accepted answer. And I found that actually the OP wants to express that, for a sample table like:
m_id | v_id | timestamp
------------------------
6 | 1 | 11
34 | 2 | 12
34 | 3 | 13
6 | 4 | 14
6 | 5 | 15
he wants to select all columns based only on (group by)m_id and (order by)timestamp.
Then the above sql won't work. If you still don't get it, imagine you have more columns than m_id | v_id | timestamp, e.g m_id | v_id | timestamp| columnA | columnB |column C| .... With group by, you can only select those "group by" columns and aggreate functions in the result.
By far, you should have understood the accepted answer.
What's more, check row_number function introduced in MySQL 8.0:
https://www.mysqltutorial.org/mysql-window-functions/mysql-row_number-function/
Finding top N rows of every group
It does the simlar thing as the accepted answer.
Some answers are wrong. My MySQL gives me error.
select m_id,v_id,max(timestamp) from table group by m_id;
#abinash sahoo
SELECT m_id,v_id,MAX(TIMESTAMP) AS TIME
FROM table_name
GROUP BY m_id
#Vikas Garhwal
Error message:
[42000][1055] Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'testdb.test_table.v_id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
Why make it so complicated? This worked.
SELECT m_id,v_id,MAX(TIMESTAMP) AS TIME
FROM table_name
GROUP BY m_id
Just you need to desc with asc. Write the query like below. It will return the values in ascending order.
SELECT * FROM table GROUP BY m_id ORDER BY m_id asc;