HiveBrain v1.2.0
Get Started
← Back to all entries
snippetsqlMinor

How to transpose/convert rows as columns in mysql

Submitted by: @import:stackexchange-dba··
0
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 |

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

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.