I have a table with two teams and frag counts
| id | teamA_name | teamA_frags | teamB_name | teamB_frags |
| 1 | 5 | 3 | 7 | 9 |
| 2 | 5 | 4 | 7 | 1 |
| 3 | 3 | 2 | 6 | 4 |
| 4 | 3 | 8 | 6 | 8 |
Is it possible to sum up all frags and present this data like that?
| team | frags |
| 5 | 7 |
| 7 | 10 |
| 3 | 10 |
| 6 | 12 |
EDIT 1: I tried queries with group by and group concat, but they are not giving me the output I wanted. For example:
SELECT teamA_name, teamB_name, SUM(teamA_frags), SUM(teamB_frags) FROM Table;
This is summing up frags OK, but printing teams next to eachother. My knowledge of SQL is limited.
Basically, you need to unpivot and re-aggregate. Here is one approach:
select team, sum(frags)
from ((select teamA_name as team, teamA_frags as frags
from t
) union all
(select teamB_name as team, teamB_frags as frags
from t
)
) t
group by team;
Related
I have a MySQL table like this:
+------+--------+--------+
| ID | UserID | Score |
+------+--------+--------+
| 1 | 3 | 12 |
| 2 | 3 | 11 |
| 3 | 3 | 12 |
| 4 | 2 | 14 |
| 5 | 4 | 8 |
| 6 | 2 | 13 |
+------+--------+--------+
From this I want to top 3 scores from entire table and a top score from particular user
+------+--------+--------+
| ID | UserID | Score |
+------+--------+--------+
| 4 | 2 | 14 |
| 6 | 2 | 13 |
| 3 | 3 | 12 |
| 5 | 4 | 8 |
+------+--------+--------+
Is this something I can get done in a single query?
Any help is appreciated
Thanks in advance!
spoiler alert ;)
(SELECT * FROM tableA ORDER BY score DESC LIMIT 3)
UNION
(SELECT * FROM tableB WHERE UserID = 4 ORDER BY score DESC LIMIT 1);
For certain definitions of "single query", sure... If you're willing to use sub queries or a union.
The best performance will probably come from two queries, but you can join them in a UNION for convenience if you wish.
I have a table with the following columns that I am trying to create a view from in order to create a report, I need to get the sum of completed hours for a particular class but with a specific filter:
| PK_CLASS_DAYS_ID | FK_MAIN_ID | FK_CLASS_ID | CLASS_DAY | OUTCOME | CLASS_DATE | HOURS |
|------------------|------------|-------------|-----------|---------|------------|-------|
| 1 | 27452 | 137 | 1 | *15 | 2015-11-15 | 8 |
| 2 | 27452 | 137 | 2 | *15 | 2015-11-16 | 8 |
| 3 | 27452 | 137 | 4 | *15 | 2015-11-18 | 8 |
| 4 | 27452 | 137 | 5 | BS15 | 2015-11-19 | 8 |
| 5 | 27452 | 2 | 1 | *16 | 2001-01-01 | 8 |
| 6 | 27452 | 48 | 1 | *16 | 2016-01-12 | 8 |
| 7 | 27452 | 48 | 2 | *16 | 2016-02-27 | 4 |
| 8 | 27452 | 2 | 1 | *17 | 2017-07-01 | 8 |
| 9 | 27452 | 137 | 1 | *16 | 2016-07-16 | 8 |
I need to find the SUM of hours completed for each class (FK_CLASS_ID) for every student in my table (currently I have filtered it to ID 27452 for testing purposes) while applying the following filter for each class (FK_CLASS_ID):
(1)CLASS_DAY must be distinct
(2)CLASS_OUTCOME must begin with "*"
(3)CLASS_DATE must be the most recent, while still having the previous two conditions. The resulting view should be as follows:
| PK_CLASS_DAYS_ID | FK_MAIN_ID | FK_CLASS_ID | Hrs |
|------------------|-------------|--------------|------|
| 1 | 27452 | 137 | 32 |
| 2 | 27452 | 2 | 8 |
| 3 | 27452 | 48 | 12 |
The furthest I've gotten with trying to accomplish this, is the following select statement:
SELECT
t1.CLASS,
SUM(class_hours) as Hrs,
GROUP_CONCAT('D',classes_days.class_day) as DaysList,
main.FULLNAME
FROM
classes t1
INNER JOIN classes_days ON classes_days.FK_CLASS_ID = t1.CLASS_ID
INNER JOIN main ON main.PK_MAIN_ID = classes_days.FK_MAIN_ID
WHERE
main.PK_MAIN_ID = 27452
GROUP BY FK_CLASS_ID
ORDER BY CLASS
For what you're wanting to accomplish, you would need to filter your joins with the desired summation queries and provide the joining on the desired criteria from the retrieved recordset.
Basing it off your provided query and desired results, it should look like:
SELECT
`t1`.`CLASS`,
SUM(`class_hours`.`HOURS`) AS `Hrs`,
GROUP_CONCAT('D', `class_hours`.`CLASS_DAY` ORDER BY `class_hours`.`CLASS_DAY`) AS `DaysList`,
`main`.`FULLNAME`
FROM `classes` AS `t1`
INNER JOIN (
#Filter the total hours by student, class, and day
SELECT `class_dates`.`FK_MAIN_ID`, `class_dates`.`CLASS_DAY`, `class_dates`.`FK_CLASS_ID`, SUM(`class_dates`.`HOURS`) as `HOURS`
FROM (
#Filter Most Recent Days beginning with star, by most recent date
SELECT `classes_days`.*
FROM `classes_days`
WHERE `classes_days`.`OUTCOME` LIKE '*%'
ORDER BY `CLASS_DATE` DESC
) AS `class_dates`
GROUP BY `class_dates`.`FK_MAIN_ID`, `class_dates`.`CLASS_DAY`, `class_dates`.`FK_CLASS_ID`
) AS `class_hours`
ON `class_hours`.`FK_CLASS_ID` = `t1`.`CLASS_ID`
INNER JOIN `main`
ON `main`.`PK_MAIN_ID` = `class_hours`.`FK_MAIN_ID`
GROUP BY `class_hours`.`FK_MAIN_ID`, `class_hours`.`FK_CLASS_ID`
ORDER BY `FULLNAME`, `CLASS`;
Resulting In:
| CLASS | Hrs | DaysList | FULLNAME |
|---------|-----|-------------|----------|
| History | 8 | D1 | Joe |
| Math | 32 | D1,D2,D4 | Joe |
| Science | 12 | D1,D2 | Joe |
| Math | 10 | D1,D2 | Mike |
Example: http://sqlfiddle.com/#!9/d5828/1
Original query of table is the top query. The subquery join example is the bottom query result. Removed the PK_MAIN_ID criteria to show it working against multiple entries
Do keep in mind that MySQL GROUP BY + ORDER BY does not always yield the desired results, and should be filtered using a subquery, which is demonstrated in the join subquery in order to get the most recent dates that begin with *.
i am loosing it over the following problem:
i have a table with participants and points. each participant can have up to 11 point entries of which i only want the sum of the top 6.
in this example lets say we want the top 2 of 3
+----+---------------+--------+
| id | participantid | points |
+----+---------------+--------+
| 1 | 1 | 11 |
+----+---------------+--------+
| 2 | 3 | 1 |
+----+---------------+--------+
| 3 | 3 | 4 |
+----+---------------+--------+
| 4 | 2 | 3 |
+----+---------------+--------+
| 5 | 1 | 5 |
+----+---------------+--------+
| 6 | 2 | 10 |
+----+---------------+--------+
| 7 | 2 | 9 |
+----+---------------+--------+
| 8 | 1 | 3 |
+----+---------------+--------+
| 9 | 3 | 4 |
+----+---------------+--------+
as a result i want something like
+---------------+--------+
| participantid | points |
+---------------+--------+
| 2 | 19 |
+---------------+--------+
| 1 | 16 |
+---------------+--------+
| 3 | 8 |
+---------------+--------+
(it should be ordered DESC by the resulting points)
is this at all possible with mysql? in one query?
oh and the resulting participant ids should be resolved into the real names from another 'partcipant' table where
+----+------+
| id | name |
+----+------+
| 1 | what |
+----+------+
| 2 | ev |
+----+------+
| 3 | er |
+----+------+
but that should be doable with a join at some point... i know...
Using one of the answers from ROW_NUMBER() in MySQL for row counts, and then modifying to get the top.
SELECT ParticipantId, SUM(Points)
FROM
(
SELECT a.participantid, a.points, a.id, count(*) as row_number
FROM scores a
JOIN scores b ON a.participantid = b.participantid AND cast(concat(a.points,'.', a.id) as decimal) <= cast(concat(b.points,'.', b.id) as decimal)
GROUP BY a.participantid, a.points, a.id
) C
WHERE row_number IN (1,2)
GROUP BY ParticipantId
Had an issue with ties until I arbitrarily broke them with the id
I have a query consisting of multiple joins and I am wondering whether it can be re-written to improve performance.
I have 2 tables as follows (I have removed non-important columns for this example):
slots
------------------------------------------
| id | name | slot_1 | slot_2 | slot_3 |
------------------------------------------
| 1 | Bob | 1 | 2 | 3 |
| 2 | Jim | 4 | 3 | 3 |
| 3 | Alf | 1 | 2 | 5 |
------------------------------------------
(There are 25 slots in total, each in it's own column)
slot_details
-----------------------------------
| id | stat_1 | stat_2 | stat_3 |
-----------------------------------
| 1 | 1 | 5 | 6 |
| 2 | 4 | 31 | 23 |
| 3 | 6 | 5 | 7 |
| 4 | 7 | 4 | 9 |
| 5 | 2 | 3 | 5 |
-----------------------------------
(There are 10 stats in total)
The query is as follows:
SELECT
slots.name,
slot_1_details.stat_1 AS slot_1_stat_1,
slot_1_details.stat_2 AS slot_1_stat_2,
slot_1_details.stat_3 AS slot_1_stat_3,
slot_2_details.stat_1 AS slot_2_stat_1,
slot_2_details.stat_2 AS slot_2_stat_2,
slot_2_details.stat_3 AS slot_2_stat_3,
slot_3_details.stat_1 AS slot_3_stat_1,
slot_3_details.stat_2 AS slot_3_stat_2,
slot_3_details.stat_3 AS slot_3_stat_3
FROM
slots
LEFT JOIN
slot_details AS slot_1_details
ON (
slot_1_details.id = slots.slot_1
)
LEFT JOIN
slot_details AS slot_2_details
ON (
slot_2_details.id = slots.slot_2
)
LEFT JOIN
slot_details AS slot_3_details
ON (
slot_3_details.id = slots.slot_3
)
WHERE (
slots.id = 1
)
The expected outcome of this query would be as follows:
| name | slot_1_stat_1 | slot_1_stat_2 | slot_1_stat_3 | slot_2_stat_1 | slot_2_stat_2 | slot_2_stat_3 | slot_3_stat_1 | slot_3_stat_2 | slot_3_stat_3 |
|bob | 1 | 5 | 6 | 4 | 31 | 23 | 6 | 5 | 7 |
Unfortunately I am not in a situation where I can change the tables.
Thank you for the help!
maybe
SELECT * FROM slots s LEFT JOIN slot_details sd ON s.id=sd.id
but i'm not sure because the query you posted is very confusing.
what are the keys of those tables?
I have two tables, rating:
+-----------+-----------+-------------+----------+
| rating_id | entity_id | rating_code | position |
+-----------+-----------+-------------+----------+
| 1 | 1 | Quality | 0 |
| 2 | 1 | Value | 0 |
| 3 | 1 | Price | 0 |
+-----------+-----------+-------------+----------+
And rating_option
+-----------+-----------+------+-------+----------+
| option_id | rating_id | code | value | position |
+-----------+-----------+------+-------+----------+
| 1 | 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 2 | 2 |
| 3 | 1 | 3 | 3 | 3 |
| 4 | 1 | 4 | 4 | 4 |
| 5 | 1 | 5 | 5 | 5 |
| 6 | 2 | 1 | 1 | 1 |
| 7 | 2 | 2 | 2 | 2 |
| 8 | 2 | 3 | 3 | 3 |
| 9 | 2 | 4 | 4 | 4 |
| 10 | 2 | 5 | 5 | 5 |
| 11 | 3 | 1 | 1 | 1 |
| 12 | 3 | 2 | 2 | 2 |
| 13 | 3 | 3 | 3 | 3 |
| 14 | 3 | 4 | 4 | 4 |
| 15 | 3 | 5 | 5 | 5 |
+-----------+-----------+------+-------+----------+
I need a SQL query (not application level, must stay in the database) which will select a set of ratings randomly. A sample result would look like this, but would pick a random value for each rating_id on subsequent calls:
+-----------+-----------+------+-------+----------+
| option_id | rating_id | code | value | position |
+-----------+-----------+------+-------+----------+
| 1 | 1 | 1 | 1 | 1 |
| 8 | 2 | 3 | 3 | 3 |
| 15 | 3 | 5 | 5 | 5 |
+-----------+-----------+------+-------+----------+
I'm totally stuck on the random part, and grouping by rating_id has been a crap shoot so far. Any MySQL ninjas want to take a stab?
Thanks,
Joe
EDIT: I've tried rand() in a bunch of combinations, and I'm sure that it will be necessary to create the randomness of the result, but I cannot figure out how to return one random row for each of the rows in rating. I cannot use order by rand() limit 1 because I need three rows, and order by rand() limit 3 won't give me one of each rating_id, which is the ultimate goal. I need a combination of rand() and either subqueries or joins so that I can ensure one of each rating_id.
Alright, a little messy, but seems to do the job. Someone may know what they're doing better than I do that can clean this up:
SELECT random.rating_id, random.rand_option_id, r3.code, r3.value, r3.position
FROM
(SELECT r.rating_id,
(SELECT r2.option_id
FROM rating_option r2
WHERE r2.rating_id = r.rating_id
ORDER BY RAND() LIMIT 1) AS 'rand_option_id'
FROM rating_option r
GROUP BY r.rating_id
) random
LEFT JOIN rating_option AS r3 ON r3.option_id = rand_option_id
Results (varies every time, of course):
+-----------+----------------+------+-------+----------+
| rating_id | rand_option_id | code | value | position |
+-----------+----------------+------+-------+----------+
| 1 | 4 | 4 | 4 | 4 |
| 2 | 6 | 1 | 1 | 1 |
| 3 | 13 | 3 | 3 | 3 |
+-----------+----------------+------+-------+----------+
You could use the rand() function to do sorting in a select on the rating table.
For example:
select rating_id from rating order by rand() limit 1
As clarified in your comments, and the other posts above
select * from rating_option order by rand()
will return all records in a random order... However, if you want only X number, then inclue that as the limit as noted by others
select * from rating_option order by rand() limit 5 (or whatever number)
Have you looked into the rand() function?
SELECT column FROM table
ORDER BY RAND()
LIMIT 1
http://www.petefreitag.com/item/466.cfm
http://dev.mysql.com/doc/refman/5.0/en/mathematical-functions.html#function_rand
Sample code
select *
from rating_option
group by rating_id
order by rand()