MySQL中的动态查询

时间:2013-04-04 07:58:29

标签: mysql dynamic pivot unpivot

我有下表。

/------------------------------------\
| LocID | Year | Birth | Death | Abc |
|------------------------------------|
|  1    | 2011 | 100   | 60    | 10  |
|------------------------------------|
|  1    | 2012 | 98    | 70    | 20  |
|.....                               |
\------------------------------------/

我需要输出(Condition LocID = 1)

/---------------------\
| Event | 2011 | 2012 |
|---------------------|
| Birth |  100 |  98  |
|---------------------|
| Death |  60  |  70  |
|---------------------|
| Abc   |  10  |  20  |
\---------------------/

该表可能包含更多基于各种要求的字段...因此,行数将取决于字段数(忽略LOCID和YEAR)。列是不变的。 仅为2年(将给予年度2012年,然后需要显示2011年和2012年)。

基本上需要将列名称作为行值,将列值作为列标题...

任何帮助......

1 个答案:

答案 0 :(得分:8)

为了获得您想要的结果,您需要当前数据从列移植到行中,然后将year数据从行转移到列中。

MySQL没有PIVOT或UNPIVOT函数,因此您需要使用UNION ALL查询来取消隐藏,并使用CASE表达式来聚合函数。

如果您有一定数量的值,那么您可以硬编码与此类似的值:

select locid,
  event,
  max(case when year = 2011 then value end) `2011`,
  max(case when year = 2012 then value end) `2012`
from
(
  select LocId, Year, 'Birth' event, Birth value
  from yt
  union all
  select LocId, Year, 'Death' event, Death value
  from yt
  union all
  select LocId, Year, 'Abc' event, Abc value
  from yt
) d
group by locid, event;

请参阅SQL Fiddle with Demo

但是如果您将拥有未知数量的值,那么您将需要使用预准备语句来生成动态SQL。代码类似于以下内容:

SET @sql = NULL;
SET @sqlUnpiv = NULL;
SET @sqlPiv = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'select locid, year, ''',
      c.column_name,
      ''' as event, ',
      c.column_name,
      ' as value 
      from yt '
    ) SEPARATOR ' UNION ALL '
  ) INTO @sqlUnpiv
FROM information_schema.columns c
where c.table_name = 'yt'
  and c.column_name not in ('LocId', 'Year')
order by c.ordinal_position;

SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'max(CASE WHEN year = ',
      year,
      ' THEN value else null END) AS `',
      year, '`'
    )
  ) INTO @sqlPiv
FROM yt;

SET @sql 
  = CONCAT('SELECT locid,
              event, ', @sqlPiv, ' 
            from 
            ( ',  @sqlUnpiv, ' ) d
            group by locid, event');

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

SQL Fiddle with Demo。两个查询的结果是:

| LOCID | EVENT | 2011 | 2012 |
-------------------------------
|     1 |   Abc |   10 |   20 |
|     1 | Birth |  100 |   98 |
|     1 | Death |   60 |   70 |