snippetsqlMinor
How to transpose/convert rows as columns in mysql
Viewed 0 times
rowscolumnstransposeconvertmysqlhow
Problem
I have table structures like below
Subjects Table
```
+----+------+------+--------+---------+
| id | C_Id | G_Id | status | subject |
+----+------+------+--------+---------+
| 1 | 13 | 4 | 1 | Telugu |
| 2 | 13 | 4 | 1 | Hindi |
| 3 | 13 | 4 | 1 | English |
| 4 | 13 | 4 | 1 | Maths |
| 5 | 13 | 4 | 1 | Physics |
| 6 | 13 | 4 | 1 | Biology |
| 7 | 13 | 4 | 1 | Social |
+----+------+------+--------+---------+
+----+-----+-----+--------+--------+-------+-------+-------+
| id | Cid | Gid | Examid | rollno | subId | Marks | paper |
+----+-----+-----+--------+--------+-------+-------+-------+
| 1 | 13 | 4 | 1 | 1 | 1 | 14.50 | 1 |
| 2 | 13 | 4 | 1 | 2 | 1 | 12.00 | 1 |
| 3 | 13 | 4 | 1 | 1 | 2 | 13.00 | 1 |
| 4 | 13 | 4 | 1 | 2 | 2 | 15.00 | 1 |
| 5 | 13 | 4 | 1 | 1 | 3 | 16.00 | 1 |
| 6 | 13 | 4 | 1 | 2 | 3 | 18.00 | 1 |
| 7 | 13 | 4 | 1 | 1 | 4 | 19.00 | 1 |
| 8 | 13 | 4 | 1 | 2 | 4 | 23.00 | 1 |
| 9 | 13 | 4 | 1 | 1 | 5 | 21.00 | 1 |
| 10 | 13 | 4 | 1 | 2 | 5 | 24.00 | 1 |
| 11 | 13 | 4 | 1 | 1 | 6 | 20.00 | 1 |
| 12 | 13 | 4 | 1 | 2 | 6 | 19.00 | 1 |
| 13 | 13 | 4 | 1 | 1 | 7 | 20.00 | 1 |
| 14 | 13 | 4 | 1 | 2 | 7 | 21.00 | 1 |
| 15 | 13 | 4 | 2 | 1 | 1 | 45.00 | 2 |
| 16 | 13 | 4 | 2 | 2 | 1 | 40.00 | 2 |
| 17 | 13 | 4 | 2 | 1 | 1 | 32.00 | 3 |
| 18 | 13 | 4 | 2 | 2 | 1 | 33.00 | 3 |
| 19 | 13 | 4 | 2 |
Subjects Table
```
+----+------+------+--------+---------+
| id | C_Id | G_Id | status | subject |
+----+------+------+--------+---------+
| 1 | 13 | 4 | 1 | Telugu |
| 2 | 13 | 4 | 1 | Hindi |
| 3 | 13 | 4 | 1 | English |
| 4 | 13 | 4 | 1 | Maths |
| 5 | 13 | 4 | 1 | Physics |
| 6 | 13 | 4 | 1 | Biology |
| 7 | 13 | 4 | 1 | Social |
+----+------+------+--------+---------+
+----+-----+-----+--------+--------+-------+-------+-------+
| id | Cid | Gid | Examid | rollno | subId | Marks | paper |
+----+-----+-----+--------+--------+-------+-------+-------+
| 1 | 13 | 4 | 1 | 1 | 1 | 14.50 | 1 |
| 2 | 13 | 4 | 1 | 2 | 1 | 12.00 | 1 |
| 3 | 13 | 4 | 1 | 1 | 2 | 13.00 | 1 |
| 4 | 13 | 4 | 1 | 2 | 2 | 15.00 | 1 |
| 5 | 13 | 4 | 1 | 1 | 3 | 16.00 | 1 |
| 6 | 13 | 4 | 1 | 2 | 3 | 18.00 | 1 |
| 7 | 13 | 4 | 1 | 1 | 4 | 19.00 | 1 |
| 8 | 13 | 4 | 1 | 2 | 4 | 23.00 | 1 |
| 9 | 13 | 4 | 1 | 1 | 5 | 21.00 | 1 |
| 10 | 13 | 4 | 1 | 2 | 5 | 24.00 | 1 |
| 11 | 13 | 4 | 1 | 1 | 6 | 20.00 | 1 |
| 12 | 13 | 4 | 1 | 2 | 6 | 19.00 | 1 |
| 13 | 13 | 4 | 1 | 1 | 7 | 20.00 | 1 |
| 14 | 13 | 4 | 1 | 2 | 7 | 21.00 | 1 |
| 15 | 13 | 4 | 2 | 1 | 1 | 45.00 | 2 |
| 16 | 13 | 4 | 2 | 2 | 1 | 40.00 | 2 |
| 17 | 13 | 4 | 2 | 1 | 1 | 32.00 | 3 |
| 18 | 13 | 4 | 2 | 2 | 1 | 33.00 | 3 |
| 19 | 13 | 4 | 2 |
Solution
In order to do that you have to use dynamic SQL.
To simplify things on the client side it's better to wrap it in a stored procedure.
In your case such procedure might look like
Note: JOINs with
Then on client side you just do
Sample output:
| ROLLNO | STDNM | TELUGU2 | TELUGU3 | HINDI1 | ENGLISH2 | ENGLISH3 | MATHS2 | MATHS3 | PHYSICS1 | BIOLOGY1 | SOCIAL2 | SOCIAL3 |
-------------------------------------------------------------------------------------------------------------------------------------
| 1 | Student 1 | 45 | 32 | 80 | 39 | 41 | 34 | 32 | 31 | 33 | 35 | 43 |
| 2 | Student 2 | 40 | 33 | 89 | 38 | 45 | 38 | 33 | 34 | 31 | 31 | 38 |
Here is SQLFiddle demo
To simplify things on the client side it's better to wrap it in a stored procedure.
In your case such procedure might look like
DELIMITER $
CREATE PROCEDURE sp_exam(IN _cid INT, IN _examid INT)
BEGIN
SET SESSION group_concat_max_len = (7 * 1024);
SET @sql = NULL;
SELECT GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(CASE WHEN m.subid = ', subid,
' AND m.paper = ', paper,
' THEN m.marks END) ', subject, paper))
INTO @sql
FROM tbl_cmarks m JOIN tbl_subjects s
ON m.subid = s.id
WHERE cid = _cid
AND examid = _examid;
SET @sql = CONCAT(
'SELECT a.rollno, a.stdnm, ', @sql,
' FROM tbl_cmarks m JOIN tbl_admission a
ON m.rollno = a.rollno
WHERE m.cid = ', _cid,
' AND m.examid = ', _examid,
' GROUP BY a.rollno, a.stdnm');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$
DELIMITER ;Note: JOINs with
tbl_classes and tbl_subjects have been removed since you don't fetch anything from the former and you don't need later for conditional grouping (ids used instead).Then on client side you just do
CALL sp_exam(13, 2);Sample output:
| ROLLNO | STDNM | TELUGU2 | TELUGU3 | HINDI1 | ENGLISH2 | ENGLISH3 | MATHS2 | MATHS3 | PHYSICS1 | BIOLOGY1 | SOCIAL2 | SOCIAL3 |
-------------------------------------------------------------------------------------------------------------------------------------
| 1 | Student 1 | 45 | 32 | 80 | 39 | 41 | 34 | 32 | 31 | 33 | 35 | 43 |
| 2 | Student 2 | 40 | 33 | 89 | 38 | 45 | 38 | 33 | 34 | 31 | 31 | 38 |
Here is SQLFiddle demo
Code Snippets
DELIMITER $$
CREATE PROCEDURE sp_exam(IN _cid INT, IN _examid INT)
BEGIN
SET SESSION group_concat_max_len = (7 * 1024);
SET @sql = NULL;
SELECT GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(CASE WHEN m.subid = ', subid,
' AND m.paper = ', paper,
' THEN m.marks END) ', subject, paper))
INTO @sql
FROM tbl_cmarks m JOIN tbl_subjects s
ON m.subid = s.id
WHERE cid = _cid
AND examid = _examid;
SET @sql = CONCAT(
'SELECT a.rollno, a.stdnm, ', @sql,
' FROM tbl_cmarks m JOIN tbl_admission a
ON m.rollno = a.rollno
WHERE m.cid = ', _cid,
' AND m.examid = ', _examid,
' GROUP BY a.rollno, a.stdnm');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;CALL sp_exam(13, 2);Context
StackExchange Database Administrators Q#47902, answer score: 7
Revisions (0)
No revisions yet.