以这种方式旋转数据称为枢轴。不幸的是,MySQL 没有枢轴函数,因此您必须使用聚合函数和CASE
表达式来复制它。
示例数据:用于此查询
CREATE TABLE Table1
(`user_id` int, `date` datetime, `value` int)
;
INSERT INTO Table1
(`user_id`, `date`, `value`)
VALUES
(1, '2013-01-01 00:00:00', 100),
(2, '2013-01-01 00:00:00', 200),
(1, '2013-01-02 00:00:00', 500)
;
CREATE TABLE Table2
(`user_id` int, `user_names` varchar(4))
;
INSERT INTO Table2
(`user_id`, `user_names`)
VALUES
(1, 'John'),
(2, 'Tim')
;
如果您知道要转换为列的所有值(对于您的示例names
),那么您可以对它们进行硬编码,SQL 将与此类似:
select
date,
max(case when rownum = 1 then value end) as John,
max(case when rownum = 2 then value end) as Tim
from
(
select date, value, user_names,
@row:=case when @prev=date then @row else 0 end + 1 as rownum,
@prev:=date
from
(
select t1.date, t1.value, t2.user_names
from table1 t1
inner join table2 t2
on t1.user_id = t2.user_id
order by date, user_names
) d, (SELECT @row:=0, @prev:=null) r
order by date, user_names
) src
group by date
请参阅SQL Fiddle with Demo。如您所见,我必须实现用户变量来为日期内的每个名称分配一个行号。这告诉您将有多少不同的名称值变成列。
但是,对于您的情况,每个日期的名称数量未知,因此您需要在准备好的语句中使用动态 SQL 。
在这种情况下,代码将类似于:
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'max(case when rownum = ',
rownum,
' then value end) AS `',
user_names, '`'
)
) INTO @sql
from
(
select date, value, user_names,
@row:=case when @prev=date then @row else 0 end + 1 as rownum,
@prev:=date
from
(
select t1.date, t1.value, t2.user_names
from table1 t1
inner join table2 t2
on t1.user_id = t2.user_id
order by date, user_names
) d, (SELECT @row:=0, @prev:=null) r
order by date, user_names
) src;
SET @sql = CONCAT('SELECT date, ', @sql, '
from
(
select date, value, user_names,
@row:=case when @prev=date then @row else 0 end + 1 as rownum,
@prev:=date
from
(
select t1.date, t1.value, t2.user_names
from table1 t1
inner join table2 t2
on t1.user_id = t2.user_id
order by date, user_names
) d, (SELECT @row:=0, @prev:=null) r
order by date, user_names
) src
group by date');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
请参阅SQL Fiddle with Demo。两个版本都会给出结果:
| DATE | JOHN | TIM |
--------------------------------------------------
| January, 01 2013 00:00:00+0000 | 100 | 200 |
| January, 02 2013 00:00:00+0000 | 500 | (null) |