Finding the most rented car of each year in SQL - mysql

I have tables as follows:
Car(id, make, ....)
Deal(id,datetime,car_id,....)
I want to write a query that would return a year, and a car make for the cars that have the most deals (ie the most deal ids) and the number of deals for that car make.
I started out,
SELECT YEAR(D.datetime) AS the_year, C.make, COUNT(D.id) AS num
FROM Deal D, Car C
WHERE D.car_id=C.id
GROUP BY the_year
Unfortunately, this has returned the year and the total number of deals.
So I am thinking to create this within another table and then call MAX(tbl.num), but I am confused on the syntax.
Can somebody help me out please?

This is an interesting problem. What you are looking for is specifically called the "mode" in statistics. In MySQL, you would get this by using variables or the group_conat()/substring_index()` trick. I'll show the latter:
SELECT the_year,
substring_index(group_concat(cd.make order by num desc), ',', 1) as the_mark
FROM (SELECT YEAR(D.datetime) AS the_year, C.make, COUNT(D.id) AS num
FROM Deal D JOIN
Car C
ON D.car_id = C.id
GROUP BY the_year, c.make
) cd
GROUP BY the_year;
EDIT:
The version using variables:
SELECT the_year,
substring_index(group_concat(cd.make order by num desc), ',', 1) as the_mark
FROM (SELECT YEAR(D.datetime) AS the_year, C.make, COUNT(D.id) AS num,
#rn := if(#year = YEAR(D.datetime), #rn + 1, 1) as rn,
#year := YEAR(D.datetime)
FROM Deal D JOIN
Car C
ON D.car_id = C.id CROSS JOIN
(SELECT #year := 0, #rn := 0) vars
GROUP BY the_year, c.make
ORDER BY the_year, num DESC
) cd
WHERE rn = 1;

Related

MySQL SUM TOP 2 RECORDS FOR EACH CATEGORY

I have a table for students scores, am trying to sum top 2 marks for all student for a particular category.I have search for similar post but have not gotten correct answer
I have tried summing the marks but am only getting result for two students instead of all students and it does not give me correct value.
SELECT SUM(marks) as totalmarks,stdid
FROM (( select marks,stdid
from finalresult
where `subjectcategory` = 1
AND `classId`='3' AND `year`='2018'
AND `term`='2' AND `type`='23'
order by marks desc
LIMIT 2 ))t1
GROUP BY stdid
An auxiliary subquery might be used for iteration
SELECT
stdid, marks
FROM
(
SELECT stdid, marks,
#rn := IF(#iter = stdid, #rn + 1, 1) AS rn,
#iter := stdid
FROM finalresult
JOIN (SELECT #iter := NULL, #rn := 0) AS q_iter
WHERE `subjectcategory` = 1
AND `classId`='3'
AND `year`='2018'
AND `term`='2'
AND `type`='23'
ORDER BY stdid, marks DESC
) AS T1
WHERE rn <= 2
this solution ignores ties and takes only two for each Student ID.
Demo
In MySQL 8+, you would do:
SELECT stdid, SUM(marks) as totalmarks
FROM (SELECT fr.*,
ROW_NUMBER() OVER (PARTITION BY stdid ORDER BY marks DESC) as seqnm
FROM finalresult fr
WHERE subjectcategory = 1 AND
classId = 3 AND
year = 2018 AND
term = 2 AND
type = 23
) fr
WHERE seqnum <= 2
GROUP BY stdid;
Note that I removed the single quotes. Things that look like numbers probably are. And you should not mix type -- put the quotes back if the values really are stored as strings.
In earlier versions, probably the simplest method is to use variables, but you have to be very careful about them. MySQL does not guarantee the order of evaluation of variables in SELECT, so you cannot assign a variable in one expression and use it in another.
A complicated expression solves this. Also, it is best to sort in a subquery (the latest versions of MySQL 5+ require this):
SELECT stdid, SUM(marks) as totalmarks
FROM (SELECT fr.*,
(#rn := IF(#s = stdid, #rn + 1,
IF(#s := stdid, 1, 1)
)
) as seqnum
FROM (SELECT fr.*
FROM finalresult fr
WHERE subjectcategory = 1 AND
classId = 3 AND
year = 2018 AND
term = 2 AND
type = 23
ORDER BY stdid, marks DESC
) fr CROSS JOIN
(SELECT #s = '', #rn := 0) params
WHERE seqnum <= 2
GROUP BY stdid;

How to rank mysql with groupby

Guy I am trying to ranking some data from my database, and I notice that it's going very wrong when I put the group by clause;
SET #rank=0;
SELECT #rank:=#rank+1 AS RankSemGenero
,a.nome AS Artista
,f.nome AS Musica
,SUM(rnk.total) AS Tocadas
,rnk.mes AS Mes
,rnk.dia AS Dia
,current_timestamp() AS Criado_Em_Sem_Genero
,23 AS RankComGenero
,current_timestamp() AS Criado_Em_Com_Genero
/*,CASE rnk.categoria
WHEN 1 then 'AM'
WHEN 2 then 'FM'
WHEN 3 then 'Web'
WHEN 4 then 'Comunitaria'
END AS Categoria_Radio*/
,'Todas' AS TipoEmissora
,5 AS Relevancia_Emissora
,'Nacional' AS Local
,5 AS Relevancia_Local
,1 AS fl_ativo
FROM rnk201901 rnk
LEFT JOIN artistas a ON rnk.artista = a.id
LEFT JOIN fonogramas f ON rnk.fonograma = f.id
WHERE rnk.dia = 10
-- AND rnk.fonograma = 35876
-- GROUP BY rnk.fonograma
ORDER BY rnk.total DESC;
This code above bringing the information on the right way 1 until ....
But if I change the GROUP BY line, I am receiving something like: 1700 instead of 1.
GROUP BY rnk.fonograma
Any idea how to handle this group by counting 1 by 1?
Thanks!!
You need to use a subquery, when using variables with group by:
select (#rank := #rank + 1) as rank, t.*
from (<your aggregation query here with order by>) t cross join
(select #rank := 0) params;

MySQL UPDATE ranking query works locally, not on server

I have a sports pools database with tables:
pools (id, name, sport, type, season, startRound, endRound)
entries (poolId, userId, entryId, poolPoints, poolRank)
picks (poolId, userId, entryId, round, pick, pickResult, pickPoints)
I can query and sum the pickPoints into poolPoints by pool/user/entry. I was then using the query shown below to update the poolRank based on poolPoints highest to lowest. I am 95% certain it worked both locally and on my server, previously. Now it does not work on the server and I can't figure out why.
Queries:
-- get current round and set as variable
SELECT round FROM hockey_games WHERE gameDate <= CURDATE()
ORDER BY gameDate DESC LIMIT 1 INTO #round;
-- rank pick'em players (overall)
UPDATE mop_survivor_entries b
INNER JOIN (
SELECT poolId, userId, entryId, poolPoints, rank FROM (
SELECT poolId, userId, entryId, poolPoints,
#curRank := IF(#prevPool != poolId, 1, IF(#prevRank = poolPoints, #curRank, #incRank)) AS rank,
#incRank := IF(#prevPool != poolId, 2, #incRank + 1),
#prevRank := poolPoints,
#prevPool := poolId
FROM mop_pools c, mop_survivor_entries e,
(SELECT #curRank :=0, #prevRank := NULL, #prevPool := 604, #incRank := 1) r
WHERE c.id = e.poolId
AND sport = 'hockey'
AND type = 'pickem'
AND season = 2017
AND startRound <= #round
AND endRound >= #round
ORDER BY poolId ASC, poolPoints DESC
) s
) a ON b.poolId = a.poolId AND b.userId = a.userId AND b.entryId = a.entryId
SET poolRank = rank;
I thought it might have something to do with my user-defined variables resetting but research isn't turning up much in the way of answers.
I tried running the queries through PHP and with phpMyAdmin with same (no change) results.
There is a slight difference in MySQL versions. Local 5.6.3; server 5.5.58 ... but again, feel it did work previously. Appreciate any help someone can give.

Mysql query is really slow. How do I increase the speed of the query?

I want to the latest results for my patients. The following sql returns 69,000 results after 87 seconds in mysqlworkbench. I have made both 'date' and 'patientid' columns as index.
select Max(date) as MaxDate, PatientID
from assessment
group by PatientID
I think my table has approximately 440,000 in total. Is it because that my table is 'large'?
Is there a way to increase the speed of this query, because I will have to embed this query inside other queries. For example like below:
select aa.patientID, assessment.Date, assessment.result
from assessemnt
inner join
(select Max(date) as MaxDate, PatientID
from assessment
group by PatientID) as aa
on aa.patientID = assessment.patientID and aa.MaxDate = assessment.Date
The above will give me the latest assessment results for each patient. Then I will also embed this piece of code to do other stuff... So I really need to speed up things. Anyone can help?
I wonder if this version would have better performance with the right indexes:
select a.patientID, a.Date, a.result
from assessemnt a
where a.date = (select aa.date
from assessment aa
where aa.patientID = a.patientID
order by aa.date desc
limit 1
);
Then you want an index on assessment(patientID, date).
EDIT:
Another approach uses an index on assessment(patient_id, date, result):
select a.*
from (select a.patient_id, a.date, a.result,
(#rn := if(#p = a.patient_id, #rn + 1,
if(#p := a.patient_id, 1, 1)
)
) as rn
from assessment a cross join
(select #p := -1, #rn := 0) params
order by patient_id desc, date desc
) a
where rn = 1;

Select multiple top3 from database

I would like to create a database view. I have got table, which contains records about the peoples, which solved some logical examples during year and they got points for that.
I need to create view from SQL query, but I have got a problem - I need to get TOP 3 users per every year by one query.
SELECT solver, year, SUM(points) as TotalPoints
FROM solving
GROUP BY solver, year
ORDER BY year, TotalPoints DESC
I got solvers per years sorted by points and year. I know I need to use limit, but I also know I will need one Select more, but I dont know where.
There are several ways to solve this in MySQL. Probably the most efficient is to use variables. The following enumerates the values:
SELECT yt.*,
(#rn := if(#y = year, #rn + 1,
if(#y := year, 1, 1)
)
) as seqnum
FROM (SELECT solver, year, SUM(points) as TotalPoints
FROM solving
GROUP BY solver, year
) yt CROSS JOIN
(SELECT #y := 0, #rn := 0) vars
ORDER BY year, TotalPoints DESC;
Then use this as a subquery to get the top three:
SELECT yt.*
FROM (SELECT yt.*,
(#rn := if(#y = year, #rn + 1,
if(#y := year, 1, 1)
)
) as seqnum
FROM (SELECT solver, year, SUM(points) as TotalPoints
FROM solving
GROUP BY solver, year
) yt CROSS JOIN
(SELECT #y := 0, #rn := 0) vars
ORDER BY year, TotalPoints DESC
) yt
WHERE seqnum <= 3;
this may help you out.
SELECT solver,
year,
SUM(points) AS TotalPoints
FROM (
SELECT solver,
year,
SUM(points) AS TotalPoints
FROM solving
ORDER BY year,
TotalPoints DESC
)
WHERE rownum <= 3
ORDER BY year,
TotalPoints DESC;