この方法でデータを回転させることをピボットと呼びます。残念ながら、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 FiddlewithDemoを参照してください。ご覧のとおり、日付内の各名前に行番号を割り当てるためにユーザー変数を実装する必要がありました。これにより、列に変換する個別の名前の値がいくつあるかがわかります。
ただし、状況によっては、各日付の名前の数が不明であるため、プリペアドステートメント内で動的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 FiddlewithDemoを参照してください。どちらのバージョンでも結果が得られます。
| DATE | JOHN | TIM |
--------------------------------------------------
| January, 01 2013 00:00:00+0000 | 100 | 200 |
| January, 02 2013 00:00:00+0000 | 500 | (null) |