mysqli SUM and MAX results - mysql

hi guys im having trouble understanding how to get a MAX() and a SUM() from a Database
my database have 3 colums id - stuff - score looks like this
id-stuf-score
1-1-2
1-1-3
1-2-1
1-2-3
1-3-1
1-3-3
i need to make a
MAX(score) where stuff=1 and id = 1
MAX(score) where stuff=2 and id = 1
MAX(score) where stuff=3 and id = 1
.
.
etc
and then a
SUM(score) all the MAX(score)
i have hundred of rows and i cant think of a way to make it happens

make subquery table derivatives for each thing you need the max of, then add them all together.
SELECT SUM(a.max+b.max+c.max) as total
FROM (
(
SELECT MAX(score) as max
FROM tablename
WHERE stuff = 1 AND id = 1
) as a,
(
SELECT MAX(score) as max
FROM tablename
WHERE stuff = 2 AND id = 1
) as b,
(
SELECT MAX(score) as max
FROM tablename
WHERE stuff = 3 AND id = 1
) as c
);
Output:
_____________
| total |
+-----------+
| 12345 |
+-----------+

Try using group by to get your max scores, then sum the results.
Records in Table
I added a few more records to so the max(score) wouldn't be the same for every stuf.
mysql> select * from stuff;
+------+------+-------+
| id | stuf | score |
+------+------+-------+
| 1 | 1 | 2 |
| 1 | 1 | 3 |
| 1 | 2 | 1 |
| 1 | 2 | 3 |
| 1 | 3 | 1 |
| 1 | 3 | 3 |
| 1 | 3 | 4 |
| 1 | 3 | 1 |
| 1 | 2 | 5 |
| 1 | 2 | 1 |
+------+------+-------+
10 rows in set (0.00 sec)
Group By
mysql> select id, max(score) as max_score from stuff group by stuf;
+------+-----------+
| id | max_score |
+------+-----------+
| 1 | 3 |
| 1 | 5 |
| 1 | 4 |
+------+-----------+
3 rows in set (0.00 sec)
Sum It Up
mysql> select sum(max_score) from (select id, max(score) as max_score
from stuff group by stuf) sum_me;
+----------------+
| sum(max_score) |
+----------------+
| 12 |
+----------------+
1 row in set (0.00 sec)
One Note
Keep in mind that if you have more ids then you will need to limit your query to whichever id you are interested in or appropriately group the last query.
mysql> select id, sum(max_score) from (select id, max(score) as max_score
from stuff group by id, stuf) sum_me group by id;

you can try this
SELECT SUM(a.max) as total
FROM (
(
SELECT MAX(score) as max
FROM tablename
GROUP BY stuf, id
) as a
);

Related

Mysql query, return only records which date is not overlapped with date of other records

To track orders i need order id from orders table and check orderdates table that order is made on specific date range. Using following query i can get id's but it will return id 3 also which is not needed.
Example: See orderdates table. First date of id 3 is overlapping with last date of id 2.
How i have to change query that id is not returned if it's first date is overlapping some other id's last date or is it even possible?
SELECT id
FROM orders
WHERE id in(
SELECT id
FROM orderdates
WHERE
orderdate BETWEEN '2017-06-01' AND '2017-06-30'
GROUP BY id);
orders
id sent
1 1
2 1
3 1
orderdates
id orderdate
1 2017-6-10
1 2017-6-11
1 2017-6-12
1 2017-6-13
2 2017-6-14
2 2017-6-15
2 2017-6-16
2 2017-6-17 <--- Last date of id 2
3 2017-6-17 <--- First date of id 3
3 2017-6-18
3 2017-6-19
3 2017-6-20
Maybe this where I compare the min date for every id against the max date for every id
select u.*
from t u
where u.id not in
(
select z.id
from
(
select s.*,t.id tid,t.mindt tmindt,t.maxdt tmaxdt
from
(
select id, min(dt) mindt,max(dt) maxdt
from t
group by id
order by id
) s
join
(select id, min(dt) mindt,max(dt) maxdt
from t
group by id
order by id
) t on
t.id <> s.id and
t.maxdt = s.mindt
) z
)
order by u.id,u.dt
given this
truncate table t;
insert into t values
(1,'2017-01-01'),(1,'2017-01-02'),
(2,'2017-01-03'),(2,'2017-01-04'),
(3,'2017-01-04')
results in
+------+------------+
| id | dt |
+------+------------+
| 1 | 2017-01-01 |
| 1 | 2017-01-02 |
| 2 | 2017-01-03 |
| 2 | 2017-01-04 |
+------+------------+
4 rows in set (0.00 sec)
given this
truncate table t;
insert into t values
(1,'2017-01-01'),(1,'2017-01-02'),
(2,'2017-01-03'),(2,'2017-01-04'),
(3,'2017-01-04'),
(4,'2017-01-04'),(4,'2017-01-06');
Result
+------+------------+
| id | dt |
+------+------------+
| 1 | 2017-01-01 |
| 1 | 2017-01-02 |
| 2 | 2017-01-03 |
| 2 | 2017-01-04 |
+------+------------+
4 rows in set (0.00 sec)
Given
truncate table t;
insert into t values
(1,'2017-01-01'),(1,'2017-01-02'),
(2,'2017-01-03'),(2,'2017-01-04'),
(3,'2017-01-04'),
(4,'2017-01-05'),(4,'2017-01-06');
result
+------+------------+
| id | dt |
+------+------------+
| 1 | 2017-01-01 |
| 1 | 2017-01-02 |
| 2 | 2017-01-03 |
| 2 | 2017-01-04 |
| 4 | 2017-01-05 |
| 4 | 2017-01-06 |
+------+------------+
6 rows in set (0.02 sec)

Make new column which is incremented by it's order

I need to make new column for my table Products -> called Order (new column). And using rails migration I need to add new column and instantly set it's order number, but it's need to be done by product_id.
What I mean I need something like:
product_id | order
1 ------------> 1
1 ------------> 2
1 ------------> 3
2 ------------> 1
2 ------------> 2
Is there a way of doing it?
EDIT :
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''order' = t1.'order'' at line 15:
update product_submissions t
join (
select
id,
product_id,
'order' from (
select id,
product_id,
#rn:= if(#prev = product_id,#rn:=#rn+1,1) as 'order',
#prev:=product_id
from product_submissions,
(select #rn:=0,#prev:=0)r
order by product_id,id
)x
)t1 on t1.id=t.id set t.'order' = t1.'order'
Consider the following
mysql> create table test (id int ,product_id int);
Query OK, 0 rows affected (0.14 sec)
mysql> insert into test values (1,1),(2,1),(3,1),(4,2),(5,2);
Now lets create the order
select
product_id,
`order` from (
select
product_id,
#rn:= if(#prev = product_id,#rn:=#rn+1,1) as `order`,
#prev:=product_id from test,(select #rn:=0,#prev:=0)r
order by product_id,id
)x ;
This will give you something as
+------------+-------+
| product_id | order |
+------------+-------+
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 1 |
| 2 | 2 |
+------------+-------+
Now lets use in update command, but before that lets add the column (in your case its already there)
mysql> alter table test add column `order` int ;
Query OK, 5 rows affected (0.29 sec)
mysql> select * from test ;
+------+------------+-------+
| id | product_id | order |
+------+------------+-------+
| 1 | 1 | NULL |
| 2 | 1 | NULL |
| 3 | 1 | NULL |
| 4 | 2 | NULL |
| 5 | 2 | NULL |
+------+------------+-------+
5 rows in set (0.00 sec)
Finally the update command
update test t
join (
select
id,
product_id,
`order` from (
select id,
product_id,
#rn:= if(#prev = product_id,#rn:=#rn+1,1) as `order`,
#prev:=product_id
from test,(select #rn:=0,#prev:=0)r
order by product_id,id
)x
)t1 on t1.id=t.id set t.`order` = t1.`order`
mysql> select * from test ;
+------+------------+-------+
| id | product_id | order |
+------+------------+-------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 1 |
| 5 | 2 | 2 |
+------+------------+-------+
5 rows in set (0.00 sec)

I need to get the average for every 3 records in one table and update column in separate table

Table Mytable1
Id | Actual
1 ! 10020
2 | 12203
3 | 12312
4 | 12453
5 | 13211
6 | 12838
7 | 10l29
Using the following syntax:
SELECT AVG(Actual), CEIL((#rank:=#rank+1)/3) AS rank FROM mytable1 Group BY rank;
Produces the following type of result:
| AVG(Actual) | rank |
+-------------+------+
| 12835.5455 | 1 |
| 12523.1818 | 2 |
| 12343.3636 | 3 |
I would like to take AVG(Actual) column and UPDATE a second existing table Mytable2
Id | Predict |
1 | 11133
2 | 12312
3 | 13221
I would like to get the following where the Actual value matches the ID as RANK
Id | Predict | Actual
1 | 11133 | 12835.5455
2 | 12312 | 12523.1818
3 | 13221 | 12343.3636
IMPORTANT REQUIREMENT
I need to set an offset much like the following syntax:
SELECT #rank := #rank + 1 AS Id , Mytable2.Actual FROM Mytable LIMIT 3 OFFSET 4);
PLEASE NOTE THE AVERAGE NUMBER ARE MADE UP IN EXAMPLES
you can join your existing query in the UPDATE statement
UPDATE Table2 T2
JOIN (
SELECT AVG(Actual) as AverageValue,
CEIL((#rank:=#rank+1)/3) AS rank
FROM Table1, (select #rank:=0) t
Group BY rank )T1
on T2.id = T1.rank
SET Actual = T1.AverageValue

Mysql Group by second column if first column is equal?

I have a table that looks like this
id | rating
1 | 1
1 | 3
1 | 1
1 | 2
2 | 3
2 | 3
2 | 1
etc,you get the idea.
Anyway, I want to end up with this result set
id | rating | num
1 | 1 | 2
1 | 3 | 1
1 | 2 | 1
2 | 3 | 2
2 | 1 | 1
So, what I want to do is group the rating's together as long as the id is the same!
I thought I could just do group by id, rating and just assumed it would group only if both columns were the same, but it doesn't it groups if either column is the same so I end up with
id | rating | num
1 | 1 | 7
How can I solve this?
I don't understand the issue you are having. This query works for me:
select
id, rating, COUNT(rating) as num
FROM rating
GROUP BY id, rating
ORDER BY id, rating ASC;
And, just to be thorough, here is my entire test session:
mysql> create table rating (id int, rating int);
Query OK, 0 rows affected (0.04 sec)
mysql> insert into rating values (1,1),(1,3),(1,1),(1,2),(2,3),(2,3),(2,1);
Query OK, 7 rows affected (0.00 sec)
Records: 7 Duplicates: 0 Warnings: 0
mysql> select id, rating, COUNT(rating) as num FROM rating GROUP BY id, rating;
+------+--------+-----+
| id | rating | num |
+------+--------+-----+
| 1 | 1 | 2 |
| 1 | 2 | 1 |
| 1 | 3 | 1 |
| 2 | 1 | 1 |
| 2 | 3 | 2 |
+------+--------+-----+
5 rows in set (0.00 sec)
you could try
SELECT id,rating,COUNT(rating) AS num
FROM table1
GROUP BY id,rating
ORDER BY id ASC
SQLFiddle Demo
SELECT id,rating,count(rating) from table group by id,rating

query to fetch records and their rank in the DB

I have a table that holds usernames and results.
When a user insert his results to the DB, I want to execute a query that will return
the top X results ( with their rank in the db) and will also get that user result
and his rank in the DB.
the result should be like this:
1 playername 4500
2 otherplayer 4100
3 anotherone 3900
...
134 current player 140
I have tried a query with union, but then I didnt get the current player rank.
ideas anyone?
The DB is MYSQL.
10x alot and have agreat weekend :)
EDIT
This is what I have tried:
(select substr(first_name,1,10) as first_name, result
FROM top_scores ts
WHERE result_date >= NOW() - INTERVAL 1 DAY
LIMIT 10)
union
(select substr(first_name,1,10) as first_name, result
FROM top_scores ts
where first_name='XXX' and result=3030);
SET X = 0;
SELECT #X:=#X+1 AS rank, username, result
FROM myTable
ORDER BY result DESC
LIMIT 10;
Re your comment:
How about this:
SET X = 0;
SELECT ranked.*
FROM (
SELECT #X:=#X+1 AS rank, username, result
FROM myTable
ORDER BY result DESC
) AS ranked
WHERE ranked.rank <= 10 OR username = 'current';
Based on what I am reading here:
Your table structure is:
+--------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| name | varchar(50) | YES | | NULL | |
| result | int(11) | YES | | NULL | |
+--------+-------------+------+-----+---------+-------+
Table Data looks like:
+---------+--------+
| name | result |
+---------+--------+
| Player1 | 4500 |
| Player2 | 4100 |
| Player3 | 3900 |
| Player4 | 3800 |
| Player5 | 3700 |
| Player6 | 3600 |
| Player7 | 3500 |
| Player8 | 3400 |
+---------+--------+
You want a result set to look like this:
+------+---------+--------+
| rank | name | result |
+------+---------+--------+
| 1 | Player1 | 4500 |
| 2 | Player2 | 4100 |
| 3 | Player3 | 3900 |
| 4 | Player4 | 3800 |
| 5 | Player5 | 3700 |
| 6 | Player6 | 3600 |
| 7 | Player7 | 3500 |
| 8 | Player8 | 3400 |
+------+---------+--------+
SQL:
set #rank = 0;
select
top_scores.*
from
(select ranks.* from (select #rank:=#rank+1 AS rank, name, result from ranks) ranks) top_scores
where
top_scores.rank <= 5
or (top_scores.result = 3400 and name ='Player8');
That will do what you want it to do
assuming your table has the following columns:
playername
score
calculated_rank
your query should look something like:
select calculated_rank,playername, score
from tablename
order by calculated_rank limit 5
I assume you have PRIMARY KEY on this table. If you don't, just create one. My table structure (because you didn't supply your own) is like this:
id INTEGER
result INTEGER
first_name VARCHAR
SQL query should be like that:
SELECT #i := #i+1 AS position, first_name, result FROM top_scores, (SELECT #i := 0) t ORDER BY result DESC LIMIT 10 UNION
SELECT (SELECT COUNT(id) FROM top_scores t2 WHERE t2.result > t1.result AND t2.id > t1.id) AS position, first_name, result FROM top_scores t1 WHERE id = LAST_INSERT_ID();
I added additional condition into subquery ("AND t2.id > t1.id") to prevent multiple people with same result having same position.
EDIT: If you have some login system, it would be better to save userid with result and get current user result using it.