How can I RANK from AVG sql? - mysql

I'm having trouble retrieving the rankings from a single line that has some uuid from that:
SELECT uuid , AVG(nodebuff+debuff+archer+builduhc+uhc+gapple)/6 as Average
from elo_ranked group by uuid
order by AVG(nodebuff+debuff+archer+builduhc+uhc+gapple)/6 desc
limit 3
I specify that the above function works and has the expected result.

Is this what you want?
SELECT uuid, AVG(nodebuff+debuff+archer+builduhc+uhc+gapple)/6 as Average ,
RANK() OVER (ORDER BY AVG(nodebuff+debuff+archer+builduhc+uhc+gapple)/6 DESC) as ranking
FROM elo_ranked
GROUP BY uuid
ORDER BY AVG(nodebuff+debuff+archer+builduhc+uhc+gapple)/6 desc
LIMIT 3;
EDIT:
To rank a specific user, use a subquery:
SELECT u.*
FROM (SELECT uuid, AVG(nodebuff+debuff+archer+builduhc+uhc+gapple)/6 as Average ,
RANK() OVER (ORDER BY AVG(nodebuff+debuff+archer+builduhc+uhc+gapple)/6 DESC) as ranking
FROM elo_ranked
GROUP BY uuid
) u
WHERE uuid = ?;
Also, I'm not sure if you need the aggregation. That would only be needed if a user had multiple rows in the elo_ranked table. If not needed, then you should use:
SELECT u.*
FROM (SELECT uuid, (nodebuff+debuff+archer+builduhc+uhc+gapple)/6 as Average ,
RANK() OVER (ORDER BY (nodebuff+debuff+archer+builduhc+uhc+gapple)/6 DESC) as ranking
FROM elo_ranked
) u
WHERE uuid = ?;
The GROUP BY has a lot of overhead, so this should be faster (unless MySQL has sophisticated optimizations to avoid the aggregation when grouping by a primary key).

Related

Distinct entries from the set

I am using the below query on the above database table but unable to get the distinct value. Help will be appreciated
SELECT DISTINCT doctor_user_id, doctor_name, score, time_in_seconds FROM basket_game_master WHERE game_id='$game_id' ORDER BY score DESC, time_in_seconds ASC LIMIT $limit
The goal is to retrieve the doctor name with unique doctor_user_id who have more score with less time_in_seconds
You can use ROW_NUMBER():
SELECT doctor_user_id, doctor_name, score, time_in_seconds
FROM (SELECT bgm.*,
ROW_NUMBER() OVER (PARTITION BY doctor_user_id ORDER BY score DESC, time_in_seconds ASC) as seqnum
FROM basket_game_master bgm
WHERE game_id = ?
) mgm
WHERE seqnum = 1
ORDER BY score DESC, time_in_seconds ASC
LIMIT ?;
Note the use of ? for the parameters. Do not munge the query string with literal values! That poses a risk for SQL injections and for hard-to-debug syntax errors.

How to find the pre-last(penultimate) value in SQL?

I have a table
/*CREATE TABLE Purchases (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
transaction_id INTEGE ,
user_id INTEGER,
purchase_date datetime,
product_type VARCHAR(30),
price INTEGER ,
);
*/
And I need to find the prelast purchase of unique users. have no clue how to to this. Better if would be MYSQL.
I'm trying to serch for the last. But even that seems bad
SELECT
user_id,
LAST_VALUE(transaction_id) OVER (
ORDER BY purchase_date
RANGE BETWEEN
UNBOUNDED PRECEDING AND
UNBOUNDED FOLLOWING
) last_purchase
FROM
purchases;
Please help me with the seraching prelast purcase(stransaction_id) of the unique visitor(user_id)
If "pre-last" means the second-to-last (i.e. penultimate) then use row_number():
select p.*
from (select p.*,
row_number() over (partition by user_id order by purchase_date desc) as seqnum
from purchases p
) p
where seqnum = 2;
Number the rows per user by date descending. Keep all rows numbered #2.
select *
from
(
select p.*, row_number() over (partition by user_id order by purchase_date desc) as rn
from purchases p
) numbered
where rn = 2;
Invert the order, then use limit and offset to select the second row.

Display SUM and LAST_VALUE groups by Year

Last forum I made question how to display values following max date, but I want to sum some values group by max date unfortunately a single value didn't want follow max date.
Here was my table:
And my query:
SELECT
SUM(pembelian) AS Buying,
SUM(penjualan) AS Selling,
SUM(penjualan)-SUM(pembelian) AS Benefit,
saldo,
MAX(tgl_lap)
FROM laporan GROUP BY DATE_FORMAT(tgl_lap,'%Y')
The results:
As we saw it, the results does work for some values but a single value (saldo) didn't following max date, guys can see the row of 2020 should be '23581800' and 2021 should be '35639800' according table.
So what I have missed?
I mean next query can solve the problem:
SELECT Buying, Selling, Benefit, saldo, last_tgl_lap
FROM laporan
JOIN (
SELECT
SUM(pembelian) AS Buying,
SUM(penjualan) AS Selling,
SUM(penjualan)-SUM(pembelian) AS Benefit,
MAX(tgl_lap) last_tgl_lap
FROM laporan
GROUP BY YEAR(tgl_lap)
) aggregated on aggregated.last_tgl_lap = tgl_lap;
Look here the example SQLize.online
If your MySQL version is 8.0 or greater you can use window function like:
SELECT
Pembelian AS Buying,
Penjualan AS Selling,
Penjualan - Pembelian AS Benefit,
Saldo,
LastDate
FROM (
SELECT
SUM(pembelian) OVER (PARTITION BY YEAR(tgl_lap) ORDER BY tgl_lap ASC) AS Pembelian,
SUM(penjualan) OVER (PARTITION BY YEAR(tgl_lap) ORDER BY tgl_lap ASC) AS Penjualan,
LAST_VALUE(saldo) OVER (PARTITION BY YEAR(tgl_lap) ORDER BY tgl_lap ASC) AS Saldo,
LAST_VALUE(tgl_lap) OVER (PARTITION BY YEAR(tgl_lap) ORDER BY tgl_lap ASC) AS LastDate,
ROW_NUMBER() OVER (PARTITION BY YEAR(tgl_lap) ORDER BY tgl_lap DESC) AS row_num
FROM laporan
) tbl
WHERE row_num = 1;
Fiddle on SQLize.online
Because of MySQL mode ONLY_FULL_GROUP_BY is disabled I think your query is not throwing error even though you have used non aggregated column saldo in the select clause.
Update after Clarification from OP
Another alternative to use window function first_value for saldo if you can,
select sum(pembelian) as Buying,
sum(penjualan) as Selling,
sum(penjualan)-sum(pembelian) as Benefit,
max(saldo) as Saldo,
max(tgl_lap) as tgl_lap
from
( select id_lap,pembelian,penjualan,tgl_lap,
first_value(saldo) over
(partition by date_format(tgl_lap,'%Y') order by tgl_lap desc) as saldo
from laporan
) l
group by date_format(tgl_lap,'%Y')
Your query is malformed. You have saldo in the SELECT, but it is not in the GROUP BY. You should be getting an error. An MySQL finally conforms to the SQL standard and to other databases in generating an error.
In MySQL 8.0, I would recommend conditional aggregation:
SELECT SUM(pembelian) AS Buying, SUM(penjualan) AS Selling,
SUM(penjualan)-SUM(pembelian) AS Benefit,
MAX(CASE WHEN seqnum = 1 THEN saldo END) as saldo,
MAX(tgl_lap)
FROM (SELECT l.*,
ROW_NUMBER() OVER (PARTITION BY YEAR(tgl_lap) ORDER BY tgl_lap DESC) as seqnum
FROM laporan l
) l
GROUP BY YEAR(tgl_lap);
Note that I replaced DATE_FORMAT() with YEAR(). It just seems clearer to me to use the appropriate date function when it is available.
In older versions, there is a hack to get the latest saldo value in each year:
SELECT SUM(pembelian) AS Buying, SUM(penjualan) AS Selling,
SUM(penjualan)-SUM(pembelian) AS Benefit,
SUBSTRING_INDEX(GROUP_CONCAT(saldo ORDER BY tgl_lap DESC), ',', 1) + 0 as saldo,
MAX(tgl_lap)
FROM laporan l
GROUP BY YEAR(tgl_lap);
This concatenates the saldo values into a string and then takes the first element. The only caveat is that the default internal length is about 1,000 characters for GROUP_CONCAT().

How can i get just the latest 2 records on each group when using GROUP_CONCAT?

SELECT id, GROUP_CONCAT(type SEPARATOR '/') as types FROM `sems` GROUP by year
I just want to get the 2 latest record on each group
If you are running MySQL 8.0, you can use row_number() for this. You need an ordering column to define the latest record, I assumed ordering_id:
select id, group_concat(type order by rn separator '/') types
from (
select id, type, row_number() over(partition by id order by ordering_id desc) rn
from sems
) t
where rn <= 2
group by id
In earlier versions, one option is to filter with a subquery:
select id, group_concat(type order by rn separator '/') types
from sems s
where s.ordering_id >= (
select s1.ordering_id
from sems s1
where s1.id = s.id
order by s1.ordering_id desc
limit 2
)
group by id
This assumes that (id, ordering_id) tuples are unique. If not, and there are ties in the top 2, all related records will be taken into account.
If your data is not too numerous, you can use:
SELECT id,
SUBSTRING_INDEX(GROUP_CONCAT(type ORDER BY ? DESC SEPARATOR '/'), '/', -2) as types
FROM `sems`
GROUP by year;.
The ? is for the column used to define "latest"

how to find index ( id ) of generic column in mysql

I have a table with name rating as this.
I am writing the query like this
SELECT user_id, sum(score) as score
FROM quiz_rashad.rating
group by user_id
order by score desc
then how I get rating index of the 12th user?
Thank you for helping.
Assuming, that "the 12th user" means the user with the ID 12:
In MySQL 8.0+ you can use dense_rank().
SELECT x.rating_index
FROM (SELECT r.user_id,
dense_rank() OVER (ORDER BY sum(r.score) DESC) rating_index
FROM quiz_rashad.rating r
GROUP BY r.user_id) x
WHERE x.user_id = 12;
Edit:
For MySQL 5.7 you have to use subqueries getting the distinct count of total scores greater than or equal the total score for the user with ID 12.
SELECT count(DISTINCT x.score) rating_index
FROM (SELECT r.user_id,
sum(r.score) score
FROM quiz_rashad.rating r
GROUP BY r.user_id) x
WHERE x.score >= (SELECT sum(r.score)
FROM quiz_rashad.rating r
WHERE r.user_id = 12)
We can try using LIMIT with OFFSET here:
SELECT user_id, SUM(score) AS score
FROM quiz_rashad.rating
GROUP BY user_id
ORDER BY score DESC
LIMIT 1 OFFSET 11;
This answer assumes that what you really want here is the record with the twelfth rank. It also assumes that no two users would be tied for the same score.