简体   繁体   中英

Pivoting for rows as columns - rating database

I have the following tables:

RATINGS

User-ID     ISBN    Book-Rating
244662  0373630689  3
19378   0812515595  2
238625  0441892604  5
180315  0140439072  1
242471  3548248950  1

BOOKS ISBN Book-Title Book-Author Year-Of-Publication Publisher 0393000753 A Reckoning May Sarton 1981 WW Norton

Using MySQL, I want to create a table that looks like this:

----- User1 User2 User3 ... ISBN1 Rating11 NaN Nan ISBN2 NaN Rating21 Rating23 ISBN3 Rating31 NaN NaN ...

I've learned how to do it for a fixed number of columns here . But how to convert the rows into columns? I have tried something like

create view BX-Book-Ratings-Extended as ( select ISBN , case when Book-Rating = "1" then 1 end as User-ID , case when Book-Rating = "2" then 2 end as User-ID , case when Book-Rating = "3" then 3 end as User-ID , case when Book-Rating = "4" then 4 end as User-ID , case when Book-Rating = "5" then 5 end as User-ID from BX-Book-Ratings )

which doesn't work - the view is empty... I also tried to adopt a solution from another thread, but keep getting a syntax error I can't identify:

SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'ifnull(SUM(case when `Book-Rating` = ''',
      `User-ID`,
      ''' then `Book-Rating` end),0) AS ',
      `User-ID`
    )
  ) INTO @sql
FROM
  `BX-Book-Ratings`;
SET @sql = CONCAT('SELECT ISBN, ', @sql, ' 
                  FROM BX-Book-Ratings 
                   GROUP BY ISBN');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

The dataset is here .

Thanks for any advice!

Your second attempt with dynamic SQL (prepare/execute) was close.
Try this query:

SET @sql = NULL;

SELECT Concat(
         'SELECT ISBN, ',
         Group_Concat( x SEPARATOR ','),
         ' FROM ratings GROUP BY ISBN '
       )
INTO @sql
FROM (
  SELECT Concat('Max( CASE WHEN User_ID = ', 
                User_ID, 
               ' THEN Book_Rating END ) As User_', 
               User_ID 
         ) As x
  FROM ratings 
  GROUP BY User_ID
  ORDER BY User_ID
) x;

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

Demo: http://rextester.com/GLJV4738

If one user can have more ratings for one book, then replace max with sum .


Unfortunately this solution is not supposed to work for more than a copule of thousand of users (columns) due to MySql limits

  • MySQL has hard limit of 4096 columns per table (so the query resultset cannot have more than 4096 columns too)
  • MySQL table has a maximum row size limit of 65,535 bytes (more on this here ), so 150.000 users in a row must for sure have more than 65 k bytes

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM