Dynamic Cross Tab in MySQL - mysql

I have the following table with the following data
Year | Age Group | Male | Female
2000 | 0 - 25 | 50 | 100
2000 | 26 above | 40 | 75
2001 | 0 - 25 | 150 | 86
2001 | 26 above | 65 | 83
I would like to create a cross tab in the following format
| Male | Female
2000 | 90 | 175
0 - 25 | 50 | 100
26 above | 40 | 75
2001 | 215 | 169
0 - 25 | 150 | 86
26 above | 65 | 83
I will be very grateful for your assistance.

SQLFiddle example:
select * from
(
select year,ageGroup,male,female from t
union all
select year,'' ageGroup,sum(male) male,sum(female) female
from t group by year
) st
order by year,agegroup

Related

How to get the opposite of a join?

I am trying to get the rows that don't exist in one table where one table called schedules (match_week, player_home_id, player_away_id) and the other table called match (match_week, Winner_id, Defeated_id) are joined. The players look at their schedule and play a match. I am trying to get a list of the scheduled matches that do not exist in the match table. The IDs in the match table can be in either column Winner_id or Defeated_id.
I have reviewed a number of Stack Exchange examples, but most use "IS NULL" and I don't have null values. I have used a Join that does give the output of the matches played. I would like the matches that have not been played.
CSV - wp_schedule_test
+----+------------+--------------+--------------+-----------------+-----------------+
| ID | match_week | home_player1 | away_player1 | player1_home_id | player1_away_id |
+----+------------+--------------+--------------+-----------------+-----------------+
| 1 | WEEK 1 | James Rives | Dale Hemme | 164 | 169 |
| 2 | WEEK 1 | John Head | David Foster | 81 | 175 |
| 3 | WEEK 1 | John Dalton | Eric Simmons | 82 | 23 |
| 4 | WEEK 2 | John Head | James Rives | 81 | 164 |
| 5 | WEEK 2 | Dale Hemme | John Dalton | 169 | 82 |
| 6 | WEEK 2 | David Foster | Eric Simmons | 175 | 23 |
| 7 | WEEK 3 | John Dalton | James Rives | 82 | 164 |
| 8 | WEEK 3 | John Head | Eric Simmons | 81 | 23 |
| 9 | WEEK 3 | Dale Hemme | David Foster | 169 | 175 |
| 10 | WEEK 4 | Eric Simmons | James Rives | 23 | 164 |
| 11 | WEEK 4 | David Foster | John Dalton | 175 | 82 |
| 12 | WEEK 4 | Dale Hemme | John Head | 169 | 81 |
+----+------------+--------------+--------------+-----------------+-----------------+
CSV - wp_match_scores_test
+----+------------+------------+------------+
| ID | match_week | player1_id | player2_id |
+----+------------+------------+------------+
| 5 | WEEK 1 | 82 | 23 |
| 20 | WEEK 1 | 164 | 169 |
| 21 | WEEK 2 | 164 | 81 |
| 25 | WEEK 2 | 82 | 169 |
| 61 | WEEK 3 | 175 | 169 |
| 62 | WEEK 4 | 175 | 82 |
| 69 | WEEK 2 | 175 | 23 |
| 85 | WEEK 3 | 164 | 82 |
| 86 | WEEK 4 | 164 | 23 |
+----+------------+------------+------------+
The output from the mysql query are the matches that have been played. I am trying to figure out how to list the matches that have not been played from the table Schedule.
CSV - MySQL Output
+------------+------------+------------+
| match_week | player1_id | player2_id |
+------------+------------+------------+
| WEEK 1 | 164 | 169 |
| WEEK 1 | 82 | 23 |
| WEEK 2 | 164 | 81 |
| WEEK 2 | 82 | 169 |
| WEEK 2 | 175 | 23 |
| WEEK 3 | 175 | 169 |
| WEEK 3 | 164 | 82 |
| WEEK 4 | 175 | 82 |
| WEEK 4 | 164 | 23 |
+------------+------------+------------+
MYSQL
select DISTINCT ms.match_week, ms.player1_id , ms.player2_id FROM
wp_match_scores_test ms
JOIN wp_schedules_test s
ON (s.player1_home_id = ms.player1_id or s.player1_away_id =
ms.player2_id)
Order by ms.match_week
The expected output is:
CSV - Desired Output
+------------+----------------+----------------+
| match_week | player_home_id | player_away_id |
+------------+----------------+----------------+
| WEEK 1 | 81 | 175 |
| WEEK 3 | 81 | 23 |
| WEEK 4 | 169 | 81 |
+------------+----------------+----------------+
The added code I would like to use is
SELECT s.*
FROM wp_schedules_test s
WHERE NOT EXISTS
(select DISTINCT ms.match_week, ms.player1_id , ms.player2_id FROM
wp_match_scores_test ms
JOIN wp_schedules_test s
ON (s.player1_home_id = ms.player1_id or s.player1_away_id =
ms.player2_id)
Order by ms.match_week)
Unfortunately, the output yields "No Rows"
You can use a LEFT JOIN to achieve the desired results, joining the two tables on matching player ids (noting that player id values in wp_match_scores_test can correspond to either player1_home_id or player1_away_id in wp_schedules_test). If there is no match, the result table will have NULL values from the wp_match_scores_test table values, and you can use that to select the matches which have not been played:
SELECT sch.*
FROM wp_schedule_test sch
LEFT JOIN wp_match_scores_test ms
ON (ms.player1_id = sch.player1_home_id
OR ms.player2_id = sch.player1_home_id)
AND (ms.player1_id = sch.player1_away_id
OR ms.player2_id = sch.player1_away_id)
WHERE ms.ID IS NULL
Output:
ID match_week home_player1 away_player1 player1_home_id player1_away_id
2 Week 1 John Head David Foster 81 175
8 Week 3 John Head Eric Simmons 81 23
12 Week 4 Dale Hemme John Head 169 81
Note that you can also use a NOT EXISTS query, using the same condition as I used in the JOIN:
SELECT sch.*
FROM wp_schedule_test sch
WHERE NOT EXISTS (SELECT *
FROM wp_match_scores_test ms
WHERE (ms.player1_id = sch.player1_home_id
OR ms.player2_id = sch.player1_home_id)
AND (ms.player1_id = sch.player1_away_id
OR ms.player2_id = sch.player1_away_id))
The output of this query is the same. Note though that conditions in the WHERE clause have to be evaluated for every row in the result set and that will generally make this query less efficient than the LEFT JOIN equivalent.
Demo on dbfiddle

How to merge two tables using single query

I have three tables named receipt, receiptdet. The receipt table store record of the receipt information while the receiptdet stores the fees details in that receipt.
Table receipt:
receiptno | payor | amount
66 | 333 | 1600
67 | 332 | 1500
68 | 215 | 300
Table receiptdet:
receiptno | fee | amount
66 | 21 | 50
66 | 33 | 50
66 | 55 | 1500
67 | 55 | 1500
68 | 12 | 100
68 | 44 | 100
68 | 22 | 100
Table fees:
Id | code | inassess
12 | Xbre | 0
21 | Drop | 0
22 | Stest | 0
33 | Perm | 0
44 | Afee | 0
55 | TFee | 1
I want a query that will display records based on the selected field if "INASSESS" field is either 0 or 1 AND SUM THE TOTAL AMOUNT ON RECEIPDET table.
DESIRED OUTPUT
receiptno | payor | SUM(receiptdet.amount) | inassess
66 | 333 | 1500 | 1
67 | 332 | 1500 | 1
OR
receiptno | payor | SUM(receiptdet.amount) | inassess
66 | 333 | 100 | 0
68 | 215 | 300 | 0
so far i have to working separate query for both table. and i want to make it as one single query if someone can help me i will greatly appreciate it. thanks in advance
SELECT
receipt.receiptno,
receipt.amount
FROM
receipt ORDER
BY LENGTH(receipt.receiptno), receipt.receiptno
SELECT
Sum(receiptdet.amount),
receiptdet.student,
feetype.inassess,
receiptdet.receiptno
FROM
receiptdet
Left Join fees ON receiptdet.fee = fees.id
Left Join feetype ON fees.feetype = feetype.id
WHERE
feetype.inassess = '0' AND
receiptdet.receiptno = '66'
You can use JOINs to put all the tables together by their linking columns, then use GROUP BY to group the data according to receiptno and inassess. One query will give you all the data you require:
SELECT r.receiptno, r.payor, SUM(rd.amount) AS fees, f.inassess
FROM receipt r
LEFT JOIN receiptdet rd ON rd.receiptno = r.receiptno
JOIN fees f ON f.id = rd.fee
GROUP BY f.inassess, r.receiptno
For your sample data, this gives:
receiptno payor fees inassess
66 333 100 0
68 215 300 0
66 333 1500 1
67 332 1500 1
SQLFiddle

MYSQL/Query: How to make table rows into column

I have 3 tables tbl_contestant , tbl_criteria and tbl_judges. And then i have 1 more table combined this 3 table as my result, tbl_score.
tbl_criteria
------------------------
crit_id | criteria_name
16 | sports
tbl_judges
------------------------
judge_id | judge_name
61 | first
62 | second
63 | third
tbl_cotestant
--------------------------------------
con_id | contestant_number | contestant_name |
1 | 1 | john |
2 | 2 | sy |
3 | 3 | Nah |
tbl_score
--------------------------------------------------
score_id | crit_id | judge_id | contestant_number | score
1 | 16 | 61 | 1 | 25
2 | 16 | 61 | 2 | 25
3 | 16 | 61 | 3 | 25
4 | 16 | 62 | 1 | 25
5 | 16 | 62 | 2 | 73
6 | 16 | 62 | 3 | 59
7 | 16 | 63 | 1 | 70
8 | 16 | 63 | 2 | 80
9 | 16 | 63 | 3 | 70
How can i achieve this output, judge_id row turns into column based on crit_id
contestant_number | contestant_name | 16_judge_61 | 16_judge_62 | 16_judge_63 | total
1 | john | 25 | 25 | 70 |
2 | sy | 25 | 73 | 80 |
3 | Nah | 25 | 59 | 70 |
Please correct my query
SELECT DISTINCT(c.contestant_number) , contestant_name , j1.sports as
16_judge_61, j2.sports as 16_judge_62, j3.sports as 16_judge_63 from
tbl_criteria , tbl_score, tbl_contestant c
LEFT JOIN tbl_ // <-- i have no idea how start from here joining those 4 tables together
You could use CASE WHEN to solve this.
SELECT
s.contestant_number,
c.contestant_name,
SUM(CASE WHEN s.crit_id='16' AND s.judge_id='61' THEN s.score END) as 16_judge_61,
SUM(CASE WHEN s.crit_id='16' AND s.judge_id='62' THEN s.score END) as 16_judge_62,
SUM(CASE WHEN s.crit_id='16' AND s.judge_id='63' THEN s.score END) as 16_judge_63,
SUM(s.score) as Total
FROM tbl_score s
INNER JOIN tbl_contestant c ON s.contestant_number = c.contestant_number
GROUP BY s.contestant_number
see SQL Fiddle http://sqlfiddle.com/#!9/9efa5/1

Pivot table query in mysql

Is there a way to do a query in mysql with this scenario.
i have a table
group_name | cost_period | books_cost | others_cost
group_A | 1/01/2015 | 100 | 200
group_A | 1/02/2015 | 56 | 86
group_A | 1/01/2015 | 22 | 222
group_A | 1/03/2015 | 30 | 40
group_B | 1/02/2015 | 50 | 10
group_B | 1/02/2015 | 45 | 10
group_B | 1/01/2015 | 22 | 15
group_C | 1/02/2015 | 45 | 20
and i want it to have this format after the query
JAN-2015 FEB-2015 MAR_2015 total
group_A
sum of book cost 122 56 30 208
sum of others cost 422 86 40 548
group_B
sum of book cost 22 95 0 117
sum of others cost 15 20 0 45
group_C
sum of book cost 0 45 0 45
sum of others cost 0 20 0 20
is there a way this is possible by a query to avoid using a pivot tool once data is gathered? since jasper's crosstabs are not that flexible
thanks

SQL sub queries - one alias column

course_completions
+-----------------------------------------------+
| id coursemodid userid state timemodified |
+-----------------------------------------------+
| 370 23 2 1 1433582890 |
| 329 24 89 1 1427771915 |
| 333 30 39 1 1428309816 |
| 332 32 39 1 1428303307 |
| 327 33 40 1 1427689703 |
| 328 34 89 1 1427710711 |
| 303 35 41 1 1410258482 |
| 358 36 99 1 1432020067 |
| 365 25 2 1 1433142455 |
| 304 26 69 1 1410717866 |
| 353 37 95 1 1430387005 |
| 416 38 2 1 1438972465 |
| 300 27 70 1 1409824001 |
| 302 29 74 1 1412055704 |
| 297 30 2 1 1409582123 |
| 301 133 41 1 1410255923 |
| 336 133 91 1 1428398435 |
| 364 133 40 1 1433142348 |
| 312 133 85 1 1425863621 |
+-----------------------------------------------+
course_modules
+------------------+
| id course |
+------------------+
| 23 6 |
| 24 6 |
| 25 6 |
| 26 6 |
| 27 6 |
| 28 6 |
| 29 8 |
| 30 8 |
| 31 8 |
| 32 8 |
| 33 8 |
| 34 5 |
| 35 5 |
| 36 5 |
| 37 5 |
| 38 5 |
| 39 9 |
| 40 9 |
| 41 9 |
+------------------+
course_mod_settings
+--------------------------------------+
|id course modinstance |
+--------------------------------------+
| 27 8 30 |
| 28 8 31 |
| 29 8 32 |
| 30 8 33 |
| 31 6 23 |
| 32 6 24 |
| 33 6 25 |
| 34 6 26 |
| 35 6 27 |
| 36 6 28 |
| 37 9 39 |
| 38 9 40 |
| 39 9 41 |
+--------------------------------------+
I was trying about to frame two sub queries in one SQL statement like I want the count of 'criteria mod settings' table values in one column and count of 'course_completions' table values in one column for a particular user along with course.
There shouldn't be relation between count(cms.id) and count(cc.id) except course id, because count(cms.id) is the count of user modules and count(cc.id) is the settings count set by default.
OUTPUT:
COURSE USERID count(cms.id) count(cc.id)
6 89 3 6
6 39 7 6
6 40 5 6
8 69 3 4
8 2 0 4
8 95 4 4
COURSE : getting courseid
USERID : getting userid
count(cms.id) : getting the count of user completed modules.
count(cc.id) : getting the count of settings (ex: For course 6, settings count has 6 and for course 4, settings count has 3.
SELECT cm.course
,cc.userid
,count(cc.coursemodid) AS usermodules
,(
SELECT count(ccc.id)
FROM course_mod_settings cms
INNER JOIN course_modules cm ON cms.course = cm.course
) AS modsettings
FROM course_completions cc
INNER JOIN course_modules cm ON cc.coursemodid = cm.id
WHERE cc.STATE = 1
GROUP BY cm.cours
,cc.userid
I have read your comment above.
Have you tried something like this?
I didn't test the query, it's just a thought.
I might be wrong.
SELECT cms.course AS COURSE, cc.userid AS USERID, COUNT(cms.id), COUNT(cc.id) FROM
course_completions AS cc
INNER JOIN course_modules AS cm ON cc.coursemodid = cm.id
INNER JOIN course_mod_settings AS cms cm.course = cms.course
WHERE cc.state = 1
GROUP BY cm.course, cc.userid