-2

可能重复:
连接两个表(具有 1-M 关系),其中第二个表需要“展平”为一行

尽管我对 sql 课程进行了介绍,但目前我无法弄清楚这一点。

我有两张桌子:

表格1:

    user_id date  value
    ids     dates values

表2:

    user_id user_names
    ids     names

我想要一个显示以下结果的 MYSQL 查询:

    /   name1  name2  name3 etc
  date1 val1-1 val1-2 val1-3 
  date2 val2-1 val2-2 val2-3

我记得有办法做到这一点,对吧?任何帮助,将不胜感激。

4

3 回答 3

1

以这种方式旋转数据称为枢轴。不幸的是,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) |
于 2013-01-30T10:50:34.983 回答
0

使用内部连接连接两个表并保存为视图,然后将其用作原始数据,PIVOT 结果集,您将获得所需的结果。连接、视图创建和 PIVOT 都应该有大量关于 SO 的代码示例,并且在课程结束后应该很容易解决。

于 2013-01-30T05:08:31.927 回答
0

是的,有一种方法可以做到这一点............它被称为 PIVOT 表

你可以参考这个

MySQL 数据透视表(将行转换为列)

于 2013-01-30T05:15:58.317 回答