SQL query to rebuild a table using its dynamic row data for column names

拥有回忆 提交于 2019-12-14 02:36:23

问题


My existing table is like this:

ID   Grant   Subtotal       Month
1   Hatch   144.56         Nov-2012
2   NIH     240.9          Nov-2012
3   NSF     100.7          Nov-2012
4   Other   276.67         Nov-2012
5   NSF     234.53         Oct-2012
6   DOE     214.35         Oct-2012
7   Hatch   321.54         Oct-2012
8   Other   312.35         Oct-2012
9   NSF     156.89         Sep-2012
10  Hatch   147.99         Sep-2012
11  Other   245.67         Sep-2012
12  State   148.66         Sep-2012

The table lists monthly expenses on each grant. As time goes by, the row number is increasing. Within the grant column, the names remain the same most of the time. When a new grant is available, it will appear here. This happens not very often.

Now I want to plot the data for a chart so people can see how much is spent each month for each grant. For this purpose, I would like to reshape the table like this:

ID   Month          DOE   Hatch     NIH     NSF     Other      State
1   Nov-2012             144.56   240.9    100.7    276.67  
2   Oct-2012     214.35  321.54           234.53    312.35  
3   Sep-2012             147.99           156.89    245.67     148.66

The desired new table keeps column Month (distinct) but will use all the data values of the Grant column (distinct) in the original table as column names (dynamic). These new columns take the corresponding data values of column Subtotal as their data.

Could someone help build the query? Thanks a lot.

BTW: I am using MySQL/PHP. I am a newbie. Any sample code is highly appreciate.


回答1:


This is basically a PIVOT but MySQL does not have PIVOT function. So you will want to replicate this using an aggregate function and a CASE statement. If you know the number of Grant values that you have then you can hard-code the query similar to this:

select 
  Month,
  sum(case when `grant`='DOE' then subtotal else 0 end) DOE,
  sum(case when `grant`='Hatch' then subtotal else 0 end) Hatch,
  sum(case when `grant`='NIH' then subtotal else 0 end) NIH,
  sum(case when `grant`='NSF' then subtotal else 0 end) NSF,
  sum(case when `grant`='Other' then subtotal else 0 end) Other,
  sum(case when `grant`='State' then subtotal else 0 end) State
from yourtable
group by month

See SQL Fiddle with Demo

Now, if you have an unknown number of values for Grant, then you can use a prepared statement to generate a dynamic version of this query:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'sum(case when `Grant` = ''',
      `Grant`,
      ''' then Subtotal else 0 end) AS `',
      `Grant`, '`'
    )
  ) INTO @sql
FROM yourtable;


SET @sql = CONCAT('SELECT month, ', @sql, ' 
                  FROM yourtable 
                  group by month');


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

See SQL Fiddle with Demo

Both produce the same result:

|    MONTH |  HATCH |   NIH |    NSF |  OTHER |    DOE |  STATE |
-----------------------------------------------------------------
| Nov-2012 | 144.56 | 240.9 |  100.7 | 276.67 |      0 |      0 |
| Oct-2012 | 321.54 |     0 | 234.53 | 312.35 | 214.35 |      0 |
| Sep-2012 | 147.99 |     0 | 156.89 | 245.67 |      0 | 148.66 |


来源:https://stackoverflow.com/questions/13348850/sql-query-to-rebuild-a-table-using-its-dynamic-row-data-for-column-names

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!