【问题标题】:SQL query horizontal display and join [duplicate]SQL查询水平显示和连接[重复]
【发布时间】:2013-01-30 05:02:51
【问题描述】:

可能重复:
Join two tables (with a 1-M relationship) where the second table needs to be ‘flattened’ into one row

虽然我参加了 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

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

【问题讨论】:

  • 如果你想拥有动态水平列,你不能在 MySQL 中真正做到这一点
  • @ExplosionPills:有“动态SQL”之类的东西,MySQL 支持。
  • @rs 谢谢。它解释了类似的情况,但是当列名已知并且被硬编码到查询中时。 “扁平化”也不是我想使用的术语。

标签: php mysql sql pivot dynamic-sql


【解决方案1】:

以这种方式旋转数据称为 pivot。不幸的是,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。如您所见,我必须实现用户变量来为日期内的每个名称分配一个行号。这告诉您将有多少不同的名称值变成列。

但对于您的情况,每个日期的名称数量未知,因此您需要在 prepared statement 中使用动态 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) |

【讨论】:

  • 非常感谢您提供了非常丰富的回复。可以从 php 代码内部调用此查询,该代码可以首先运行查询以获取名称数组,然后创建一个“硬编码”查询以与您的第一个示例一起使用。如果可能的话,我会尽量避免使用准备好的语句进入 sql。
  • @Tim 乐于助人。 :) 我想我会给出这两种解决方案,这样你就可以看到如何执行转换。如果此答案对您有帮助或对您的问题的任何答案有帮助,请务必通过其左侧的复选标记接受它。它将帮助未来的访问者,您将获得网站代表接受。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    你可以参考this一个。

    MySQL pivot tables (transform rows to columns)

    【讨论】:

      猜你喜欢
      • 2012-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-04
      • 2012-11-29
      相关资源
      最近更新 更多