Cumulative sum with max date group by month year and id - mysql

Now i need to make similar query but need to several criteria
Here is my table
`transaksi` (`transid`, `idpinj`, `tanggal`,`sisapokok`, `sisajasa`
(1, 1, '2018-01-01', 1000, 100, 1),
(2, 1, '2018-01-05', 1000, 100, 3),
(3, 2, '2018-02-04', 1000, 100, 4),
(4, 2, '2018-02-08', 1000, 100, 5),
(5, 1, '2018-02-19', 1000, 100, 3),
(6, 3, '2018-02-22', 1000, 100, 2),
(7, 2, '2018-03-09', 1000, 100, 3),
(8, 3, '2018-03-10', 1000, 100, 3)
(9, 3, '2018-03-12', 1000, 100, 4)
(10, 1, '2018-03-17', 1000, 100, 4)
(11, 4, '2018-03-19', 1000, 100, 3)
(12, 2, '2018-03-20', 1000, 100, 4)
DB Fiddle table
From the table above i need to get output as follow
Month sisapokok sisajasa
Jan-2018 1000 100 ->row2
Feb-2018 4000 400 ->+ row3+5
Mar-2018 12000 1200 ->+ row9+10+11+12
First I need to get sum(sisapokok) and sum(sisajasa) for each idpinj where date is max(tanggal), status between 3 and 4. This value then sum as total per month
Make cumulative sum each month for the last 12 month
I try this query but it get the max(date) from all records not max(date) by month and each idpinj.
SELECT a.idpinj,a.sisapokok
FROM transaksi a
INNER JOIN
(
SELECT idpinj, MAX(tanggal) tgl
FROM transaksi
GROUP BY idpinj
) b ON a.idpinj = b.idpinj
AND a.tanggal = b.tgl
ORDER BY `a`.`idpinj` ASC

Not sure exactly what you are asking for but see if this helps:
select monthyear, sum(sisapokok)sisapokok, sum(sisajasa)sisajasa from (
select cast(month(tanggal) as varchar)+'-'+cast(year(tanggal) as varchar) monthyear, sum(sisapokok)sisapokok, sum(sisajasa)sisajasa
from #transaksi
group by cast(month(idpinj) as varchar)+'-'+cast(year(tanggal) as varchar) , tanggal) a
group by monthyear

Based on the fiddle data
select yyyy,mm,
#s:=#s+sisapokok sisapokok,
#t:=#t+sisajasa sisajasa
from
(
select yyyy,mm,sum(sisapokok) sisapokok,sum(sisajasa) sisajasa
from
(
select year(tanggal) yyyy,month(tanggal) mm, sisapokok,sisajasa
from transaksi t
join
(
select year(tanggal) yyyy,month(tanggal) mm,idpinj,max(transid) maxid
from `transaksi`
where status in(3,4)
group by year(tanggal),month(tanggal),idpinj
) s on s.maxid = transid
) t
group by yyyy,mm
) u
,(select #s:=0,#t:=0) r
order by yyyy,mm
+------+------+-----------+----------+
| yyyy | mm | sisapokok | sisajasa |
+------+------+-----------+----------+
| 2018 | 1 | 2000 | 2003 |
| 2018 | 2 | 5000 | 2303 |
| 2018 | 3 | 13000 | 3103 |
+------+------+-----------+----------+
3 rows in set (0.00 sec)
Note the inner query finds the last relevant id and the code progresses outward to use variables to calculate running totals.

Related

use group by max() twice in another column

I use mysql query.
I want to know the date and amount of the highest salary.
I want to know if I can use max() twice as below.
The result comes out exactly as I want.
But as far as I know, you have to use only one max().
Was I mistaken?
http://sqlfiddle.com/#!9/8db0c17/4
create table test ( mid bigint , sal bigint , dt date);
insert into test values( 1, 100, '2020-01-01 00:00:00'),
( 1, 200, '2020-02-01 00:00:00'),
( 2, 100, '2020-03-01 00:00:00'),
( 2, 200, '2020-04-01 00:00:00'),
( 2, 300, '2020-05-01 00:00:00'),
( 3, 500, '2020-10-01 00:00:00');
select mid, max(sal), max(dt) from test group by mid;
mid max(sal) max(dt)
1 200 2020-02-01
2 300 2020-05-01
3 500 2020-10-01
You can use max several times in your query, but in your case, you will not get what you want.
If we change your data like this:
1, 100, 2020-01-01
1, 200, 2020-02-01
2, 100, 2020-02-01
2, 300, 2020-03-01
2, 200, 2020-04-01
2, 300, 2020-05-01
3, 500, 2020-10-01
3, 300, 2020-11-01
Your result will be:
1, 200, 2020-02-01
2, 300, 2020-05-01
3, 500, 2020-11-01
As you can see, for 3rd row we get maximum value for sal and for dt but separately.
We can use somthing like this to get the right result:
select
t.mid, max(t.dt), tmp.sal_max
from test t
join (
select t1.mid, max(t1.sal) as sal_max
from test t1
group by t1.mid) tmp on tmp.mid = t.mid AND tmp.sal_max = t.sal
group by tmp.mid;
Result:
1, 2020-02-01, 200
2, 2020-05-01, 300
3, 2020-10-01, 500
I think it is not the simplest option, but it will work.
Yes you can use max many times it should be different columns names
The other column should be in group by

Top sales making product for each year

I have two tables with following schema.
CREATE TABLE Product (
id INT AUTO_INCREMENT,
name VARCHAR(64) UNIQUE,
unit_price VARCHAR(6),
PRIMARY KEY (id)
);
CREATE TABLE Sale (
id INT AUTO_INCREMENT,
product_id INT, created_at DATETIME,
units INT, PRIMARY KEY (id),
FOREIGN KEY (product_id) REFERENCES Product(id)
);
INSERT INTO Product(name, unit_price)
VALUES
('Methadone', 30),
('Codeine', 20),
('Morphine', 40),
('Fentanyl', 10);
INSERT INTO Sale(product_id, created_at, units)
VALUES
(1, '2004-01-06 08:27:25', 8),
(4, '2004-03-05 05:21:15', 24),
(2, '2005-01-06 08:26:55', 3),
(4, '2005-03-31 01:55:25', 6),
(1, '2005-11-09 11:33:20', 2),
(4, '2006-02-15 10:46:30', 4),
(3, '2006-04-14 07:40:50', 1),
(4, '2008-01-06 08:27:25', 5),
(4, '2008-01-10 21:31:45', 3),
(1, '2008-01-28 16:07:30', 9),
(3, '2008-03-05 05:21:00', 4),
(2, '2008-03-08 18:25:50', 5),
(4, '2008-05-02 02:15:20', 1),
(4, '2008-05-05 15:19:40', 3),
(4, '2008-06-28 23:08:55', 2),
(4, '2008-07-02 12:14:00', 2),
(3, '2008-08-29 09:07:50', 1),
(2, '2008-10-22 16:56:20', 5),
(3, '2008-10-26 06:01:25', 2),
(4, '2008-12-19 13:49:55', 4),
(2, '2008-12-23 02:55:30', 4),
(1, '2009-02-15 10:43:45', 4),
(2, '2009-04-14 07:37:50', 6),
(3, '2009-06-11 04:31:25', 3),
(4, '2009-08-08 01:25:30', 12),
(1, '2010-11-09 11:33:20', 8),
(1, '2011-01-14 10:22:35', 3),
(3, '2011-03-13 07:16:10', 3),
(4, '2011-05-10 04:10:15', 4),
(4, '2011-07-07 01:04:35', 4),
(4, '2011-09-02 21:58:10', 3),
(2, '2011-10-30 18:51:45', 3),
(1, '2011-12-27 15:45:20', 1),
(4, '2012-02-23 12:43:25', 2),
(4, '2012-04-21 09:37:30', 3),
(4, '2012-06-18 06:31:20', 1),
(2, '2012-08-15 03:25:40', 4),
(2, '2013-01-14 10:23:20', 4),
(4, '2013-02-01 05:01:35', 1),
(4, '2013-03-13 07:16:55', 1),
(4, '2013-03-31 01:55:10', 2),
(4, '2013-05-10 04:11:15', 2),
(3, '2013-05-27 22:48:45', 3),
(1, '2013-07-07 01:05:20', 3),
(2, '2013-07-24 19:42:20', 4),
(4, '2013-09-02 21:59:40', 4),
(3, '2013-09-20 16:36:10', 1),
(4, '2013-10-30 18:54:00', 2),
(4, '2013-11-17 13:29:45', 1),
(4, '2013-12-27 15:48:20', 3);
I want to find top sales making product for each year sorted by year in descending order along-with the total sale made for the top selling product.
I have written the following query.
SELECT EXTRACT(YEAR FROM S.created_at) as year,
GROUP_CONCAT(DISTINCT P1.name
ORDER BY P1.name
SEPARATOR ',')as top,
MAX(S.units*P1.unit_price) as sale
FROM Sale S
INNER JOIN Product P1 ON S.product_id=P1.id
GROUP BY year
ORDER BY year desc
Expected Output:
2013 Codeine,Fentanyl,Morphine 160
2012 Codeine 80
2011 Methadone,Morphine 120
2010 Methadone 240
2009 Codeine,Fentanyl,Methadone,Morphine 120
2008 Codeine,Morphine 280
2006 Fentanyl,Morphine 40
2005 Codeine,Fentanyl,Methadone 60
2004 Fentanyl,Methadone 240
Original Output:
2013 Codeine,Fentanyl,Methadone,Morphine 120
2012 Codeine,Fentanyl 80
2011 Codeine,Fentanyl,Methadone,Morphine 120
2010 Methadone 240
2009 Codeine,Fentanyl,Methadone,Morphine 120
2008 Codeine,Fentanyl,Methadone,Morphine 270
2006 Fentanyl,Morphine 40
2005 Codeine,Fentanyl,Methadone 60
2004 Fentanyl,Methadone 240
The query was supposed to return only the top selling products, bu it's returning all the products. Could anyone provide any help?
Here is a solution for MySQL < 8.0. First, aggregate sales by year and product and filter on the top selling products with an aggregate, correlated subquery; then, aggregate by year:
select
year_at,
group_concat(name order by name) products,
total_sales
from (
select
year(s.created_at) year_at,
p.name,
sum(s.units * p.unit_price) total_sales
from Product p
inner join Sale s on s.product_id = p.id
group by year_at, p.id, p.name
having total_sales = (
select sum(s1.units * p1.unit_price) total_sales1
from Product p1
inner join Sale s1 on s1.product_id = p1.id
where year(s1.created_at) = year_at
group by s1.product_id
order by total_sales1 desc
limit 1
)
) t
group by year_at, total_sales
order by year_at desc
Demo on DB Fiddlde:
year_at | products | total_sales
------: | :---------------------------------- | ----------:
2013 | Codeine,Fentanyl,Morphine | 160
2012 | Codeine | 80
2011 | Methadone,Morphine | 120
2010 | Methadone | 240
2009 | Codeine,Fentanyl,Methadone,Morphine | 120
2008 | Codeine,Morphine | 280
2006 | Fentanyl,Morphine | 40
2005 | Codeine,Fentanyl,Methadone | 60
2004 | Fentanyl,Methadone | 240
You seem to be after this...
SELECT GROUP_CONCAT(a.name) names,a.total, a.year
FROM
( SELECT p.name
, SUM(p.unit_price*s.units) total
, YEAR(created_at) year
FROM product p
JOIN sale s
ON s.product_id = p.id
GROUP
BY year
, name
) a
JOIN
( SELECT MAX(total) total
, year
FROM
( SELECT p.name
, SUM(p.unit_price*s.units) total
, YEAR(created_at) year
FROM product p
JOIN sale s
ON s.product_id = p.id
GROUP
BY year
, name
) n
GROUP
BY year) b
ON b.year = a.year AND b.total = a.total
GROUP BY a.total, a.year
ORDER BY year DESC;
+-------------------------------------+-------+------+
| names | total | year |
+-------------------------------------+-------+------+
| Fentanyl,Codeine,Morphine | 160 | 2013 |
| Codeine | 80 | 2012 |
| Morphine,Methadone | 120 | 2011 |
| Methadone | 240 | 2010 |
| Morphine,Methadone,Fentanyl,Codeine | 120 | 2009 |
| Morphine,Codeine | 280 | 2008 |
| Morphine,Fentanyl | 40 | 2006 |
| Codeine,Methadone,Fentanyl | 60 | 2005 |
| Methadone,Fentanyl | 240 | 2004 |
+-------------------------------------+-------+------+
Here's a variant of my Scalar-Aggregate Comparison query technique that will achieve what you want in a vastly better-performing query than self-joining the aggregate results. As you can see below, this only ever performs a single join, then 3 cascaded layers of aggregation to achieve the final output.
SELECT
yr,
SUBSTRING(MAX(CONCAT(LPAD(total_sales, 16, '0'), products)), 17) AS best_seller,
MAX(total_sales) AS sales_amount
FROM (
SELECT
yr,
total_sales,
GROUP_CONCAT(name order by name) AS products
FROM (
SELECT
YEAR(s.created_at) AS yr,
p.id,
p.name,
SUM(s.units * p.unit_price) AS total_sales
FROM Product AS p
INNER JOIN Sale AS s on s.product_id = p.id
GROUP BY YEAR(s.created_at), p.id
) AS pys
GROUP BY yr, total_sales
) AS py
GROUP BY yr
ORDER BY yr DESC;
Here's a DB Fiddle demo: https://dbfiddle.uk/?rdbms=mysql_5.6&fiddle=e14ed7f396738ce064f1998bdb4310ac
try this:
Select name, year(created_at), sum(unit_price*units )
from Product p inner join sale s on p.id = s.product_id
group by name, year(created_at)
order by 2, 3 desc
If you want the top selling product for each year, use rank() and an aggregation query:
select ps.*
from (select p.name, year(s.created_at) as year, sum(p.unit_price*s.units) as sales
rank() over (partition by year(s.created_at) order by sum(p.unit_price*s.units) desc as seqnum
from Product p inner join
sale s
on p.id = s.product_id
group by name, year
) ps
where seqnum <= 1; -- You can change "1" for more rows

Mysql select query count until reach the condition with condition

I have lists of users with his points and game id. I need to find the rank of the specified user based on the game order by the max(lb_point).
I have already done the query for getting the rank based on individual game as follows.
select count(*) AS user_rank
from (
select distinct user_id
from leader_board
where lb_point >= (select max( lb_point )
from leader_board
where user_id = 1
and game_id = 2 )
and game_id = 2
) t
But i need to find the rank based on the overall game. Example i have 3 different games (1,2,3). By passing the user_id, i need to find his overall rank among all three games. Can you please help me on this?
lb_id user_id game_id lb_point
------------------------------------------------
1 1 2 670
2 1 1 200
3 1 2 650
4 1 1 400
5 3 2 700
6 4 2 450
7 2 1 550
8 2 1 100
9 1 1 200
10 2 1 100
11 1 1 200
12 2 1 100
13 1 1 200
14 2 1 100
15 1 1 200
16 2 1 100
17 1 1 200
18 2 1 100
19 1 1 200
20 2 1 100
21 1 1 200
22 2 1 800
use sandbox;
/*create table t (lb_id int, user_id int, game_id int, lb_point int);
truncate table t;
insert into t values
(1 , 1, 2, 670),
(2 , 1, 1, 200),
(3 , 1, 2, 650),
(4 , 1, 1, 400),
(5 , 3, 2, 700),
(6 , 4, 2, 450),
(7 , 2, 1, 550),
(8 , 2, 1, 100),
(9 , 1, 1, 200),
(10, 2, 1, 100),
(11, 1, 1, 200),
(12, 2, 1, 100),
(13, 1, 1, 200),
(14, 2, 1, 100),
(15, 1, 1, 200),
(16, 2, 1, 100),
(17, 1, 1, 200),
(18, 2, 1, 100),
(19, 1, 1, 200),
(20, 2, 1, 100),
(21, 1, 1, 200),
(22, 2, 1, 800);
*/
select t.*
from
(
select s.*,#rn:=#rn+1 as rank
from
(
select user_id, sum(lb_point) points
from t
where lb_id = (select t1.lb_id from t t1 where t1.user_id = t.user_id and t1.game_id = t.game_id order by t1.lb_point desc limit 1)
group by user_id
order by points desc
) s
,(select #rn:=0) rn
) t
where t.user_id = 1
The innermost query grabs the highest score per game per user and sums it.
The next query assigns a rank based on the aggregated score per user.
The outermost query selects the user.

Mysql return 0 not null in sum

Help needed please I have a table with taskId, Materials, Labour and a table with expenses in. The issue i have is that some tasks do not have and expense column in the taskenpense table so the column returns null. I need null to be 0.
` CREATE TABLE emptasks ( empTaskId INT, taskMaterials NUMERIC(8,2),taskLabour NUMERIC(8,2));
INSERT INTO emptasks VALUES
(1, 50, 50),
(2, 450.26, 50),
(3, 2505.10, 50),
(4, 2505.10, 50),
(5, 500, 500),
(6, 1000, 50);
CREATE TABLE taskexpenses (
feeID INT,
empTaskId INT,
expense NUMERIC(8,2));
INSERT INTO taskexpenses VALUES
(1, 1, 50.00),
(1, 2, 50.00),
(2, 2, 126.00),
(3, 3, 50.00),
(4, 4, 50.00),
(2, 2, 1206.00);
SELECT
p.empTaskId,
p.Labour,
p.Materials,
f.Expenses,
p.Labour + p.Materials - f.Expenses AS Total,
ROUND( (f.Expenses + p.Materials) / p.Labour * 100, 2) AS Percentage
FROM (
SELECT
empTaskId,
SUM(taskMaterials) AS Labour,
SUM(taskLabour) AS Materials
FROM emptasks
GROUP BY empTaskId
) p
LEFT JOIN (
SELECT taskexpenses.empTaskId,
SUM(expense) AS Expenses
FROM emptasks
INNER JOIN taskexpenses ON emptasks.empTaskId = taskexpenses.empTaskId
GROUP BY empTaskId
) f ON p.empTaskId = f.empTaskId
the result is
empTaskId Labour Materials Expenses Total Percentage
1 50 50 50 50 200
2 450.26 50 1382 -881.74 318.04
3 2505.1 50 50 2505.1 3.99
4 2505.1 50 50 2505.1 3.99
5 500 500 (null) (null) (null)
6 1000 50 (null) (null) (null)
I need the null value to return 0 so the sum can be worked out
FIDDLE LINK
THanks
Jon
Slightly simpler than in the answer from #Bob Jarvis is to use the IFNULL() function.
SELECT
p.empTaskId,
p.Labour,
p.Materials,
IFNULL(f.Expenses, '0') AS Expenses,
IFNULL(p.Labour + p.Materials - f.Expenses, '0') AS Total,
IFNULL(ROUND( (f.Expenses + p.Materials) / p.Labour * 100, 2), '0') AS Percentage
FROM ...
See fiddle
Use the COALESCE function:
SELECT p.empTaskId,
p.Labour,
p.Materials,
COALESCE(f.Expenses, 0) AS Expenses,
COALESCE(p.Labour, 0) + COALESCE(p.Materials, 0) - COALESCE(f.Expenses, 0) AS Total,
ROUND( (COALESCE(f.Expenses, 0) + COALESCE(p.Materials, 0)) / p.Labour * 100, 2) AS Percentage
FROM (SELECT empTaskId,
SUM(COALESCE(taskMaterials, 0)) AS Labour,
SUM(COALESCE(taskLabour, 0)) AS Materials
FROM emptasks
GROUP BY empTaskId) p
LEFT JOIN (SELECT taskexpenses.empTaskId,
SUM(COALESCE(expense, 0)) AS Expenses
FROM emptasks
INNER JOIN taskexpenses
ON emptasks.empTaskId = taskexpenses.empTaskId
GROUP BY empTaskId) f
ON p.empTaskId = f.empTaskId
Note that here I've put COALESCE on just about everything which might possibly be NULL. If you only want to put it on the Expenses column change it to be what you want.
Best of luck.

How do I get the sum of each persons best ten scores of the season?

I have a database of results for a season of 25 games. However only each persons best ten scores count.
Can anybody tell me how to sum just the top ten scores of each person AND show the minimum score that was used in that sum (their tenth best).
The database has PlayerName, TournamentID, Points
eg.
- TounamentID PlayerName Points
- 1 Jo 100
- 1 Tel 50
- 1 Kevin 75
- 2 Jo 100
- 2 Tel 50
- 2 Kevin 75
- 3 Jo 100
- 3 Tel 50
- 3 Kevin 75
- 4 Jo 100
- 4 Tel 50
- 4 Kevin 75
- 5 Jo 100
- 5 Tel 50
- 5 Kevin 75 etc
Many thanks in advance
EDIT 1
At the moment I have this kind of working though it doesn't handle duplicate scores very well and can actual end up adding up the top 11 if there's a duplicate;
SELECT X.PlayerName, Sum(X.Points) AS SumOfPoints, Min(X.Points) AS Target
FROM SoP11PreBats AS X
WHERE (((10)>(SELECT count(*)
FROM SoP11PreBats
WHERE PlayerName = X.PlayerName
AND Points > X.Points )))
GROUP BY X.PlayerName
ORDER BY Sum(X.Points) DESC;
Something like this would work for one player at a time:
SELECT SUM(n), MIN(n) FROM
(SELECT points AS n
FROM table
WHERE PlayerName = ?
ORDER BY n DESC
LIMIT 10
)
I'm not sure how to expand it to produce a table for every player.
SELECT test.playername, sum(top10.score), MIN(top10.score)
FROM test
LEFT JOIN (SELECT playername, score FROM test ORDER BY score DESC LIMIT 10) top10
ON top10.playername = test.playername
GROUP BY test.playername
Edit: Turns out the above approach using a subselect and join is not going to do the trick. Because you limit the results in the subselect it is not going to lead to a set of max 10 records PER playername.
The next approach would be to do something like
SELECT pk, name, score from test where
pk IN (SELECT pk FROM test t2 WHERE t2.name = name ORDER BY score DESC LIMIT 10)
This could create the proper set of records to join with. However LIMIT is not supported inside an IN clause (yet). So this won't compile.
EIDT2: The final approach I can think of goes like this:
select distinct test.name
, (SELECT sum(t2.score) FROM (select t3.score FROM test t3 WHERE t3.name = test.name ORDER BY score desc LIMIT 10) t2)
, (SELECT min(t2.score) FROM (select t3.score FROM test t3 WHERE t3.name = test.name ORDER BY score desc LIMIT 10) t2)
FROM test
This one also won't compile because the most inner test.name in the where can't be resolved properly.
I don't think that what you want to do can currently be done in 1 single query on mysql, but I'm curious if someone can proof me wrong.
Ok I got it working but it's about the most nasty sql hack I could think of and I'm not sure you should even consider to put it in production like this. It also only runs on mysql:
select PlayerName, sum(Points), min(Points) from
(select distinct SoP11PreBats.PlayerName, (SELECT t2.Points FROM test t2 WHERE t2.PlayerName = SoP11PreBats.PlayerName ORDER BY Points desc LIMIT 1) as Points FROM test
UNION ALL
select distinct SoP11PreBats.PlayerName, (SELECT t2.Points FROM test t2 WHERE t2.PlayerName = SoP11PreBats.PlayerName ORDER BY Points desc LIMIT 1,1) as Points FROM test
UNION ALL
select distinct SoP11PreBats.PlayerName, (SELECT t2.Points FROM test t2 WHERE t2.PlayerName = SoP11PreBats.PlayerName ORDER BY Points desc LIMIT 2,1) as Points FROM test
UNION ALL
select distinct SoP11PreBats.PlayerName, (SELECT t2.Points FROM test t2 WHERE t2.PlayerName = SoP11PreBats.PlayerName ORDER BY Points desc LIMIT 3,1) as Points FROM test
UNION ALL
select distinct SoP11PreBats.PlayerName, (SELECT t2.Points FROM test t2 WHERE t2.PlayerName = SoP11PreBats.PlayerName ORDER BY Points desc LIMIT 4,1) as Points FROM test
UNION ALL
select distinct SoP11PreBats.PlayerName, (SELECT t2.Points FROM test t2 WHERE t2.PlayerName = SoP11PreBats.PlayerName ORDER BY Points desc LIMIT 5,1) as Points FROM test
UNION ALL
select distinct SoP11PreBats.PlayerName, (SELECT t2.Points FROM test t2 WHERE t2.PlayerName = SoP11PreBats.PlayerName ORDER BY Points desc LIMIT 6,1) as Points FROM test
UNION ALL
select distinct SoP11PreBats.PlayerName, (SELECT t2.Points FROM test t2 WHERE t2.PlayerName = SoP11PreBats.PlayerName ORDER BY Points desc LIMIT 7,1) as Points FROM test
UNION ALL
select distinct SoP11PreBats.PlayerName, (SELECT t2.Points FROM test t2 WHERE t2.PlayerName = SoP11PreBats.PlayerName ORDER BY Points desc LIMIT 8,1) as Points FROM test
UNION ALL
select distinct SoP11PreBats.PlayerName, (SELECT t2.Points FROM test t2 WHERE t2.PlayerName = SoP11PreBats.PlayerName ORDER BY Points desc LIMIT 9,1) as Points FROM test
) top10
group by name
I have a feeling this will not work:
SELECT *
FROM
( SELECT pd.PlayerName
, ( SELECT SUM(t10.Points)
FROM
( SELECT t10.Points
FROM SoP11PreBats AS t10
WHERE t10.PlayerName = pd.PlayerName
ORDER BY t10.Points DESC
LIMIT 10
) AS x
) AS Sum10
, ( SELECT t10.Points
FROM SoP11PreBats AS t10
WHERE t10.PlayerName = pd.PlayerName
ORDER BY t10.Points DESC
LIMIT 1 OFFSET 9
) AS TenthBest
FROM
( SELECT DISTINCT PlayerName
FROM SoP11PreBats
) AS pd
) AS y
ORDER BY Sum10 DESC
But this will:
SELECT pb.PlayerName AS PlayerName
, COALESCE(SUM(p.Points),0) + pb.TenthBest*(10-COUNT(p.Points))
AS SumOfPoints
, pb.TenthBest AS Target
FROM
( SELECT pd.PlayerName
, ( SELECT t10.Points
FROM SoP11PreBats AS t10
WHERE t10.PlayerName = pd.PlayerName
ORDER BY t10.Points DESC
LIMIT 1 OFFSET 9
) AS TenthBest
FROM
( SELECT DISTINCT PlayerName
FROM SoP11PreBats
) AS pd
) AS pb
LEFT JOIN SoP11PreBats AS p
ON p.PlayerName = pb.PlayerName
AND p.Points > pb.TenthBest
GROUP BY pb.PlayerName
ORDER BY SumOfPoints DESC
This works (see test output below):
set #count:=0, #player:='';
SELECT
PlayerName,
SUM(Points) as sum_top_10,
MIN(Points) as min_top_10
FROM (SELECT PlayerName, Points
FROM (SELECT
Points,
#count := if (#player != PlayerName, 0, #count + 1) as count,
#player := PlayerName as PlayerName
FROM (SELECT PlayerName, Points FROM SoP11PreBATS order by 1, 2 desc) x) y
where count < 10) z
group by 1;
Here's the test, using OP's data, plus extra rows for 'Jo' to make more than 10 rows:
create table SoP11PreBATS (TounamentID int, PlayerName text, Points int);
delete from SoP11PreBATS;
insert into SoP11PreBATS values
(1, 'Jo', 100), (1, 'Tel', 50), (1, 'Kevin', 75), (2, 'Jo', 100), (2, 'Tel', 50),
(2, 'Kevin', 75), (3, 'Jo', 100), (3, 'Tel', 50), (3, 'Kevin', 75), (4, 'Jo', 100),
(4, 'Tel', 50), (4, 'Kevin', 75), (5, 'Jo', 100), (5, 'Tel', 50), (5, 'Kevin', 75),
(5, 'Jo', 50), (6, 'Jo', 75), (7, 'Jo', 100), (8, 'Jo', 50), (9, 'Jo', 75),
(10, 'Jo', 50), (11, 'Jo', 75), (12, 'Jo', 100);
select * from SoP11PreBATS where playername = 'Jo' order by points desc;
+-------------+------------+--------+
| TounamentID | PlayerName | Points |
+-------------+------------+--------+
| 1 | Jo | 100 |
| 2 | Jo | 100 |
| 3 | Jo | 100 |
| 4 | Jo | 100 |
| 5 | Jo | 100 |
| 7 | Jo | 100 |
| 12 | Jo | 100 |
| 6 | Jo | 75 |
| 9 | Jo | 75 |
| 11 | Jo | 75 |
| 5 | Jo | 50 |
| 8 | Jo | 50 |
| 10 | Jo | 50 |
+-------------+------------+--------+
-- Inspection shows Jo should have 925 as sum and 75 as min
-- Ran query above and got:
+------------+------------+------------+
| PlayerName | sum_top_10 | min_top_10 |
+------------+------------+------------+
| Jo | 925 | 75 |
| Kevin | 375 | 75 |
| Tel | 250 | 50 |
+------------+------------+------------+
-- Test output correct
I think this works, and it only uses one derived table:
SELECT #row := 0, #pp := NULL, #min := 0;
SELECT Player,
SUM(Points) AS Points,
MIN(Points) AS MinPoints
FROM (
SELECT Player,
Points,
#row := IF(
IFNULL(#pp, '') <> Player AND NOT (#pp := Player),
1,
#row + 1
) AS Row
FROM SoP11PreBats
ORDER BY Player, Points DESC
) tmp
WHERE tmp.Row <= 10
GROUP BY Player;
Test data:
CREATE TABLE `SoP11PreBats` (
`TournamentID` int(11) NOT NULL,
`Player` varchar(255) NOT NULL,
`Points` int(11) NOT NULL
);
INSERT INTO SoP11PreBats (TournamentID, Player, Points) VALUES
(15, 'Jo', 10),
(14, 'Jo', 20),
(13, 'Jo', 30),
(12, 'Jo', 40),
(11, 'Jo', 50),
(10, 'Jo', 60),
( 9, 'Jo', 70),
( 8, 'Jo', 80),
( 7, 'Jo', 90),
( 6, 'Jo', 100),
( 5, 'Jo', 110),
( 4, 'Jo', 120),
( 3, 'Jo', 130),
( 2, 'Jo', 140),
( 1, 'Jo', 150),
( 1, 'Tel', 15),
( 2, 'Tel', 25),
( 3, 'Tel', 35),
( 4, 'Tel', 45),
( 5, 'Tel', 55),
( 6, 'Tel', 65),
( 7, 'Tel', 75),
( 8, 'Tel', 85),
( 9, 'Tel', 95),
(10, 'Tel', 105),
(11, 'Tel', 115),
(12, 'Tel', 125),
(13, 'Tel', 135),
(14, 'Tel', 145),
(15, 'Tel', 155),
( 1, 'Kevin', 10),
( 2, 'Kevin', 20),
( 3, 'Kevin', 30),
( 4, 'Kevin', 40),
( 5, 'Kevin', 50),
( 6, 'Kevin', 60),
( 7, 'Kevin', 70),
( 8, 'Kevin', 80),
( 9, 'Kevin', 90),
(10, 'Kevin', 100),
(11, 'Kevin', 110),
(12, 'Kevin', 120),
(13, 'Kevin', 130),
(14, 'Kevin', 140),
(15, 'Kevin', 150);
Result:
+--------+--------+-----------+
| Player | Points | MinPoints |
+--------+--------+-----------+
| Jo | 1050 | 60 |
| Kevin | 1050 | 60 |
| Tel | 1100 | 65 |
+--------+--------+-----------+