MySQL - get sum() of group - php

I have this table similar to MySQL - get sum() grouped max() of group
id | person | score | date | g | b | m |
-----------------------------------------------------------
1 | 32 | 444 | 2011-05 | 0 | 1 | o |
2 | 65 | 528 | 2011-05 | 1 | 0 | 1 |
3 | 77 | 455 | 2011-05 | 0 | 0 | 1 |
4 | 32 | 266 | 2011-05 | 1 | 1 | 0 |
5 | 77 | 100 | 2011-05 | 0 | 0 | 1 |
6 | 77 | 457 | 2011-05 | 1 | 0 | 0 |
7 | 77 | 457 | 2011-05 | 1 | 0 | 1 |
8 | 65 | 999 | 2011-05 | 0 | 0 | 1 |
9 | 32 | 222 | 2011-05 | 0 | 1 | 1 |
The result should be:
person | score | date | g | b | m |
-----------------------------------------------------
32 | 932 | 2012-05 | 1 | 3 | 1 |
66 | 1527 | 2012-05 | 1 | 0 | 2 |
77 | 1469 | 2012-05 | 2 | 0 | 3 |
But I couldn't achieve what I want to. I am trying to get for each person sum of its scores, g, m and b fields in each month. I'm very newbie about subqueries.
Thank you!

You can't just group by month, since the same month can appear in more than one year, so group by year as well, e.g.:
SELECT person, YEAR(`date`), MONTH(`date`),
SUM(score), SUM(b), SUM(g), SUM(m)
FROM MyTable
GROUP BY person, YEAR(`date`), MONTH(`date`)
If your date column is actually not a date type but a varchar or similar, and it contains yyyy-dd as shown, than you can just do:
SELECT person, `date`,
SUM(score), SUM(b), SUM(g), SUM(m)
FROM MyTable
GROUP BY person, `date`

Related

mysql find number of entry in a different status in descending order

I have a table like this
+----+--------+--------+
| id | ref_id | status |
+----+--------+--------+
| 1 | 3 | 1 |
| 2 | 4 | 0 |
| 4 | 6 | 0 |
| 6 | 8 | 1 |
| 8 | 10 | 0 |
| 10 | 12 | 1 |
| 12 | 14 | 1 |
| 14 | 16 | 0 |
| 16 | 18 | 0 |
| 18 | 20 | 0 |
+----+--------+--------+
I want to find the number of rows that has a status 0 in descending order continuously. In this Case number would be 3
+----+--------+--------+
| id | ref_id | status |
+----+--------+--------+
| 1 | 3 | 1 |
| 2 | 4 | 0 |
| 4 | 6 | 0 |
| 6 | 8 | 1 |
| 8 | 10 | 1 |
| 10 | 12 | 1 |
| 12 | 14 | 0 |
| 14 | 16 | 0 |
| 16 | 18 | 0 |
| 18 | 20 | 0 |
+----+--------+--------+
In this case it is four
+----+--------+--------+
| id | ref_id | status |
+----+--------+--------+
| 1 | 3 | 1 |
| 2 | 4 | 0 |
| 4 | 6 | 0 |
| 6 | 8 | 1 |
| 8 | 10 | 1 |
| 10 | 12 | 1 |
| 12 | 14 | 0 |
| 14 | 16 | 0 |
| 16 | 18 | 0 |
| 18 | 20 | 1 |
+----+--------+--------+
In this case it is 0
So far I tried is processing the rows descending and finding it through php condition . Is there any better way to do it ?
I used this code in codeigniter and get the result
$this->db->select('count(id) as number');
$this->db->from('tablename');
$this->db->where('id > (select max(id) FROM tablename where status = 1)',
NULL, FALSE);
In mysql
SELECT count(id) as number FROM tablename
WHERE id > (select max(id) FROM tablename where status = 1)

Join of 2 Tables X and Y to display Total sum() results event Table Y is empty

I have 2 tables which I need to join and sum the qty based on a requirement. Here's the tables structure.
Customer
---------------------------------------------------
ID | Name | Tel | Sex
---------------------------------------------------
1 | John | 123 XXXX | M
2 | Peter | 456 XXXX | M
3 | Alice | 789 XXXX | F
4 | Amy | 147 XXXX | F
Transaction
---------------------------------------------------
ID | CustID | TranID | Books | Pens | Rulers
---------------------------------------------------
1 | 1 | Jan | 1 | 1 | 0
2 | 1 | Feb | 1 | 0 | 0
3 | 2 | Jan | 1 | 0 | 1
4 | 2 | Jan | 1 | 0 | 0
5 | 3 | Feb | 0 | 1 | 1
6 | 4 | Feb | 1 | 1 | 0
7 | 3 | Feb | 1 | 1 | 0
8 | 4 | Feb | 0 | 0 | 1
9 | 3 | Jan | 1 | 0 | 0
10 | 2 | Jan | 1 | 1 | 0
Required Results (Sex=F, TranID=Jan, Sum:Books, Pens & Rulers)
--------------------------------------------------------------
Name | Tel | Sex | B.TOT | P.TOT | R.TOT
--------------------------------------------------------------
Alice | 789 XXXX | F | 1 | 0 | 0
Amy | 147 XXXX | F | 0 | 0 | 0
I've tried with the following SQL statement and it is working as long as the Transaction Table is NOT EMPTY.
select
`customer`.name,
`customer`.tel,
`customer`.sex,
sum(if(`transaction`.TranID = 'JAN',books,0)) as B.Tot,
sum(if(`transaction`.TranID = 'JAN',pens,0)) as P.Tot,
sum(if(`transaction`.TranID = 'JAN',rulers,0)) as R.tot,
from
`customer`
left join
`transaction`
on
`customer`.id = `transaction`.custid
where
`customer`.sex = 'F'
Group by
`customer`.id,
order by
`customer`.name ASC
How do I modify the above to show the Customer List where SEX='F' even the transaction table is totally empty?
SQL QUERY
I hope this query will resolve your problem :
SELECT
c.name,
c.tel,
c.sex,
IFNULL(SUM(t.books), 0) 'B.TOT',
IFNULL(SUM(t.pens), 0) 'P.TOT',
IFNULL(SUM(t.rulers), 0) 'R.TOT'
FROM
customer c
LEFT JOIN
`transaction` t ON t.custid = c.id AND t.TranID = 'Jan'
WHERE
c.sex = 'F'
GROUP BY c.id
ORDER BY c.name;

Group data weekly according to passed date range in mysql cake php

I have a table jobs with following data
+----+------------+--------+---------------------+
| id | project_id | status | modified |
+----+------------+--------+---------------------+
| 1 | 1 | 0 | 2014-08-23 19:48:48 |
| 2 | 1 | 0 | 2014-08-29 18:18:39 |
| 3 | 1 | 0 | 2014-08-23 19:58:55 |
| 44 | 1 | 0 | 2014-08-23 19:45:50 |
| 45 | 1 | 2 | 2014-08-03 14:38:35 |
| 46 | 1 | 3 | 2014-08-05 14:38:35 |
| 47 | 1 | 2 | 2014-08-07 14:38:35 |
| 48 | 1 | 3 | 2014-08-10 14:38:35 |
| 49 | 2 | 4 | 2014-08-14 14:38:35 |
| 50 | 1 | 0 | 2014-08-23 19:43:01 |
| 51 | 1 | 2 | 2014-08-15 14:38:35 |
| 52 | 1 | 3 | 2014-08-18 14:38:35 |
| 53 | 1 | 0 | 2014-08-23 19:49:05 |
| 54 | 1 | 4 | 2014-08-22 14:38:35 |
| 55 | 1 | 2 | 2014-09-03 14:38:59 |
| 56 | 1 | 0 | 2014-08-23 19:59:23 |
| 57 | 1 | 3 | 2014-08-27 14:38:35 |
| 58 | 1 | 4 | 2014-09-03 14:39:04 |
| 59 | 1 | 0 | 2014-08-27 17:28:45 |
| 60 | 1 | 1 | 2014-08-27 17:29:00 |
| 61 | 1 | 1 | 2014-08-27 17:29:17 |
| 62 | 1 | 0 | 2014-08-29 16:36:07 |
| 63 | 1 | 0 | 2014-08-29 16:37:24 |
| 64 | 1 | 0 | 2014-08-29 18:19:01 |
| 65 | 1 | 0 | 2014-08-29 19:17:20 |
| 66 | 1 | 1 | 2014-08-29 19:17:36 |
| 67 | 1 | 1 | 2014-08-29 19:17:54 |
| 68 | 1 | 0 | 2014-08-29 19:26:16 |
| 69 | 1 | 1 | 2014-08-29 19:26:34 |
| 70 | 1 | 1 | 2014-08-29 19:26:54 |
| 71 | 1 | 0 | 2014-08-30 19:33:59 |
| 72 | 1 | 1 | 2014-08-30 19:34:23 |
| 73 | 1 | 1 | 2014-08-30 19:35:42 |
| 74 | 1 | 1 | 2014-08-30 19:36:39 |
| 75 | 1 | 0 | 2014-08-30 19:40:52 |
| 76 | 1 | 0 | 2014-08-30 20:42:02 |
| 77 | 1 | 0 | 2014-08-30 21:27:38 |
| 78 | 1 | 1 | 2014-08-30 21:28:28 |
| 79 | 1 | 1 | 2014-08-30 21:28:59 |
| 80 | 1 | 0 | 2014-08-30 21:47:02 |
| 81 | 1 | 1 | 2014-08-30 21:47:40 |
| 82 | 1 | 1 | 2014-08-30 21:48:20 |
| 83 | 2 | 3 | 2014-08-23 18:23:12 |
| 84 | 2 | 4 | 2014-08-23 18:23:12 |
| 85 | 1 | 4 | 2014-08-23 18:23:12 |
+----+------------+--------+---------------------+
from which i want to get the data on Weekly basis according to the "from" and "to" dates i pass from front end. so lets suppose want data from '2014-07-15' to '2014-09-15' that should be clubbed weekly and gives sum of all jobs whose status is either (2,3,4) on a particular week for each project.
my result should be something like this
+--------------+---------------+---------------------+
| project_name | reviewed_jobs | modified |
+--------------+---------------+---------------------+
| Project 1 | 0 | 2014-07-15 14:38:35 |
| Project 1 | 0 | 2014-07-22 14:38:35 |
| Project 1 | 1 | 2014-07-29 14:38:35 |
| Project 1 | 3 | 2014-08-05 14:38:35 |
| Project 1 | 2 | 2014-08-12 14:38:35 |
| Project 1 | 2 | 2014-08-19 18:23:12 |
| Project 1 | 1 | 2014-08-26 19:48:48 |
| Project 1 | 2 | 2014-09-02 18:18:39 |
| Project 1 | 0 | 2014-09-09 14:38:59 |
| Project 2 | 0 | 2014-07-15 14:38:35 |
| Project 2 | 0 | 2014-07-22 14:38:35 |
| Project 2 | 0 | 2014-07-29 14:38:35 |
| Project 2 | 0 | 2014-08-05 14:38:35 |
| Project 2 | 1 | 2014-08-12 14:38:35 |
| Project 2 | 2 | 2014-08-19 18:23:12 |
| Project 2 | 0 | 2014-08-26 19:48:48 |
| Project 2 | 0 | 2014-09-02 18:18:39 |
| Project 2 | 0 | 2014-09-09 14:38:59 |
+--------------+---------------+---------------------+
what i have tried so far using raw query and cake php way :
raw query :
SELECT projects.name as project_name,
SUM(if((jobs.status=2 || jobs.status=3 || jobs.status=4), 1, 0)) as reviewed_jobs,
jobs.modified FROM jobs LEFT JOIN projects ON jobs.project_id=projects.id
WHERE jobs.modified >= '2014:08:03 00:00:00' AND jobs.modified <= '2014:09:03 23:59:59'
GROUP BY projects.name, WEEK(jobs.modified)
ORDER BY DATE(jobs.modified) ASC;
but it gives the following result
+--------------+---------------+---------------------+
| project_name | reviewed_jobs | modified |
+--------------+---------------+---------------------+
| Project 1 | 3 | 2014-08-03 14:38:35 |
| Project 1 | 2 | 2014-08-10 14:38:35 |
| Project 2 | 1 | 2014-08-14 14:38:35 |
| Project 2 | 2 | 2014-08-23 18:23:12 |
| Project 1 | 3 | 2014-08-23 19:48:48 |
| Project 1 | 1 | 2014-08-29 18:18:39 |
| Project 1 | 2 | 2014-09-03 14:38:59 |
+--------------+---------------+---------------------+
which obviously is undesired and different from what i want and it has some potential problems as
if it doesn't get data of specific date (i.e 2014-08-17 in this case) it skips that week or count from the next date which is available.
result is not according to the dates passed in query indeed it's according to the data in table(dates available in table).
CakePHP way :
$options['joins']=array(array('table' => 'projects',
'alias' => 'Project',
'type' => 'LEFT',
'conditions' => array(
'Project.id = Job.project_id',
)
));
$options['fields'] = array(
'Project.name',
'SUM(if((Job.status=2 || Job.status=3 || Job.status=4), 1, 0)) as reviewed',
'DATE(Job.modified) as modified'
);
$options['order'] = array('modified'=>'ASC');
$options['conditions']=array(
array("Job.modified >=" => $from_date->format("Y-m-d") . ' 00:00:00'),
array("Job.modified <=" => $to_date->format("Y-m-d") . ' 23:59:59')
);
$options['group'] = array('Project.name', 'WEEK(Job.modified)');
Any help would be appreciable
Thanks
In mysql you would need another table containing all the weeks dates so you can join to that too and therefore return the weeks where there are no entries in the jobs table.
Quick and dirty way to construct weeks data:
SELECT STR_TO_DATE(CONCAT(yr.yy,'-',wk1.d,wk2.d,'-01'), '%Y-%u-%w') yyyywkd FROM
(SELECT 0 d UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) wk1,
(SELECT 0 d UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) wk2,
(SELECT '2013' yy UNION SELECT '2014') yr
WHERE CONCAT(wk1.d,wk2.d) > 0 AND CONCAT(wk1.d,wk2.d) < 54
Try this in a sub query left joined to the jobs table.

how to use while loop in mysql array?

I have a table called vw_results which holds the result profile for a particular student:
idNum |courseUnit | marks | Gpp | grade| id | semseterID | sessionName
06/021| 2 | 47 | 8 | B+ | 1 | 1 | 2010/11
06/021| 3 | 56 | 7 | C | 1 | 1 | 2010/11
. | 4 | 34 | 5 | C | 1 | 1 | 2010/11
. | 5 | 34 | 0 | F | 1 | 1 | 2010/11
. | 2 | 89 | 10 | A | 1 | 2 | 2010/11
. | 3 | 45 | 4 | D | 1 | 2 | 2010/11
. | 4 | 56 | 10 | C | 1 | 2 | 2010/11
. | 2 | 67 | 12 | B+ | 2 | 1 | 2011/12
. | 1 | 70 | 15 | A | 2 | 1 | 2011/12
. | 2 | 80 | 10 | A | 2 | 2 | 2011/12
. | 3 | 90 | 5 | A | 2 | 2 | 2011/12
To calculate the GPA
"SELECT SUM( vwr.courseUnit ) cummUnit, SUM( vwr.GPP ) cummGPP, (
SUM( vwr.GPP ) / SUM( vwr.courseUnit ))cummGPA
FROM vw_result vwr
WHERE vwr.Grade NOT IN ('F') AND vwr.sessionID=".$_GET['sessionID']." AND vwr.semesterID=".$_GET['semesterID'].";"
if $_GET['sessionID']=1 and $_GET['semesterID']=2
then
|cummGPA|
|1.913 |
if $_GET['sessionID']=2 and $_GET['semesterID']=1
then
|cummGPA|
|2.730 |
if $_GET['sessionID']=2 and $_GET['semesterID']=2
then
|cummGPA|
|2.774 |
any suggestions on how to go about this?!
THANKS!
Uff, you should ask more clearly, no one will take time to understand you question. Its just that I have nothing to do..
If i understand what you want correctly then it will be:
select count(id) from vw_results group by (id, semseterID) having (id=1 and semseterID=1) or (id=1 and semseterID=2) or (id=2 and semseterID=1) or (id=2 and semseterID=2)
Hope it will work, never tried it.

Query optimization for tournament scoring tables in MySQL

I have two tables in a tournament-related database and I need to know the most optimized SQL query to generate the correct overall results. The results must show the total points scored, minus any penalties, and scores that are tied should be broken based on the person who reached that score first.
In the database tables, I have an event log where each score is added as teams proceed through the tournament, and I have another table which shows which team is part of which tournament.
Table "xTournamentTeam" (connects a team to a tournament)
=======================
+-----+------------+--------+--------------+
| nID | Team Name | TeamID | TournamentID |
+-----+------------+--------+--------------+
| 1 | Team A | 12 | 25 |
| 2 | Team B | 13 | 25 |
| 3 | Team C | 14 | 25 |
| 4 | Team D | 15 | 25 |
| 3 | Team A | 12 | 32 |
| 4 | Team B | 13 | 32 |
+-----+------------+--------+--------------+
Table "nEventLog" (records scoring during a tournament)
=================
+-----+---------------+---------+----------+----------------+-----------------------+
| nID | nTournamentID | nTeamID | nPoints | nPointsPenalty | nEventTime |
+-----+---------------+---------+----------+----------------|-----------------------+
| 1 | 25 | 15 | 100 | 0 | 1/24/2013 6:05:14 AM |
| 2 | 25 | 14 | 100 | 0 | 1/24/2013 6:29:55 AM |
| 3 | 25 | 14 | 100 | 25 | 1/24/2013 7:09:34 AM |
| 4 | 25 | 12 | 100 | 0 | 1/24/2013 7:12:28 AM |
| 5 | 25 | 12 | 100 | 0 | 1/24/2013 8:42:59 AM |
| 6 | 25 | 12 | 100 | 50 | 1/24/2013 8:43:36 AM |
| 7 | 25 | 14 | 100 | 0 | 1/24/2013 9:15:24 AM |
| 8 | 25 | 15 | 100 | 0 | 1/24/2013 9:15:27 AM |
| 9 | 32 | 12 | 100 | 0 | 1/28/2013 8:33:49 AM |
| 10 | 32 | 13 | 100 | 25 | 1/28/2013 2:15:12 PM |
| 11 | 32 | 12 | 100 | 10 | 1/28/2013 7:12:25 AM |
| 12 | 32 | 13 | 100 | 0 | 1/29/2013 7:18:06 AM |
+-----+---------------+---------+----------+----------------+-----------------------+
In the case of the above data, the query I need should generate the following results for Tournament #25:
+-------+------------+--------+--------------+---------------+---------------------+-----------------------------+
| nRank | Team Name | TeamID | TournamentID | nTotalPoints | nTotalPointsPenalty | nLatestEventTime |
+-------+------------+--------+--------------+---------------+---------------------+-----------------------------+
| 1 | Team A | 12 | 25 | 300 | 50 | 1/24/2013 8:43:36 AM |
| 2 | Team C | 14 | 25 | 300 | 25 | 1/24/2013 9:15:24 AM |
| 3 | Team D | 15 | 25 | 200 | 0 | 1/24/2013 9:15:27 AM |
| 4 | Team B | 13 | 25 | 0 | 0 | |
+-------+------------+--------+--------------+---------------+---------------------+-----------------------------+
For load purposes, I'm trying to avoid sub-queries at all costs since the final query should be as optimized as possible. The "nRank" column can be generated programatically... MySQL shouldn't have to return it, but I'm shoing it for reference.
The query I have that is the closest is this one, but it doesn't return "Team B" because they don't have any records in the "nEventLog" table for nTournamentID #25:
SELECT xTournamentTeam.nTeamName
, sum(nEventLog.nPoints) AS nTotalPoints
, xTournamentTeam.nTeamID
, max(nEventLog.nEventTime) AS nLatestEventTime
, sum(nEventLog.nPointsPenalty) AS nTotalPenaltyPoints
, xTournamentTeam.nTournamentID
FROM
xTournamentTeam
LEFT OUTER JOIN nEventLog
ON xTournamentTeam.nTeamID = nEventLog.nTeamID
WHERE
xTournamentTeam.nTournamentID = 33
AND nEventLog.nTournamentID = 33
GROUP BY
xTournamentTeam.nID
, xTournamentTeam.nTournamentID
ORDER BY
nTotalPoints DESC
, nLatestEventTime DESC
I'm certainly no expert in MySQL queries, and I've been working on this for two days without much success, so any help would be greatly appreciated.
I change your logic a little bit, I think it's working:
SELECT
xTournamentTeam.TeamName
, sum(nEventLog.nPoints) AS nTotalPoints
, xTournamentTeam.TeamID
, max(nEventLog.nEventTime) AS nLatestEventTime
, sum(nEventLog.nPointsPenalty) AS nTotalPenaltyPoints
, xTournamentTeam.TournamentID
FROM
xTournamentTeam
LEFT OUTER JOIN nEventLog
ON xTournamentTeam.TournamentID = nEventLog.nTournamentID AND xTournamentTeam.TeamID = nEventLog.nTeamID
WHERE
xTournamentTeam.TournamentID = 25
GROUP BY
xTournamentTeam.TeamID
, xTournamentTeam.TournamentID
, xTournamentTeam.TeamName
ORDER BY
nTotalPoints DESC
If you need, you can format nulls to represent 0 or something else.

Categories