【问题标题】:Can a MySQL query turn rows into columns?MySQL 查询可以将行变成列吗?
【发布时间】:2010-12-02 16:01:28
【问题描述】:

我有许多表我正试图与联接组合,但因此,结果以多行形式返回,而我希望将它们生成为新列。

成员信息表

MemberID | FirstName | LastName 
---------------------------------
   1     |   John    |  Harris
   2     |   Sarah   |  Thompson
   3     |   Zack    |  Lewis

member_dependent_information 表

MemberID | FirstName | LastName | Type
---------------------------------------
   1     |   Amy     | Harris   |  1 
   2     |   Bryan   | Thompson |  1
   2     |   Dewey   | Thompson |  2
   2     |   Tom     | Thompson |  2
   3     |   Harry   | Lewis    |  2
   3     |   Minka   | Lewis    |  1

MySQL 查询:

SELECT
    t1.FirstName,
    t1.LastName,
    t1.MemberID,
    IF(t2.Type = '1',CONCAT(t2.FirstName,' ',t2.LastName),'') AS Spouse_Name,
    IF(t2.Type = '2',CONCAT(t2.FirstName,' ',t2.LastName),'') AS Child_Name,

FROM
    member_dependent_information t2
INNER JOIN
    member_information t1
USING
    (MemberID)
ORDER BY
    t1.LastName ASC,
    t1.MemberID ASC;

理想结果

MemberID | FirstName | LastName  | Spouse_Name    | Child_Name1   | Child_Name2 
--------------------------------------------------------------------------------
   1     |   John    |  Harris   | Amy Harris     |     NULL       |   NULL    
   2     |   Sarah   |  Thompson | Bryan Thompson | Dewey Thompson | Tom Thompson    
   3     |   Zack    |  Lewis    | Mika Lewis     | Harry Lewis    |   NULL

实际结果

MemberID | FirstName | LastName  | Spouse_Name    | Child_Name 
-------------------------------------------------------------------
   1     |   John    |  Harris   | Amy Harris     |    NULL
   2     |   Sarah   |  Thompson | Bryan Thompson |    NULL  
   2     |   Sarah   |  Thompson |      NULL      | Dewey Thompson  
   2     |   Sarah   |  Thompson |      NULL      | Tom Thompson    
   3     |   Zack    |  Lewis    | Mika Lewis     |    NULL      
   3     |   Zack    |  Lewis    |      NULL      | Harry Lewis    

虽然我的查询在多行中返回“正确”数据,但它不会根据需要将结果合并为一行。

下面已经提到了关于数据透视表/交叉表的建议,但我能找到的每个参考都建议使用数学计算,或者要返回的字段数量是已知的。我不会知道这个信息,因为一个成员最多可以有 100 名家属(虽然更像是 4-8 名)

更新 #1

我觉得我离最终解决方案越来越近了。我将函数 GROUP_CONCAT 添加到我的查询中,该函数在单个列中返回所有名字,在单个列中返回所有姓氏,但仍需要将它们分成各自的列。

新功能是:

SELECT
  t1.MemberID,
  t1.FirstName,
  t1.LastName,
  GROUP_CONCAT(t2.FirstName) AS Dep_Firstnames,
  GROUP_CONCAT(t2.LastName) AS Dep_LastNames
FROM
  member_information t1
  LEFT OUTER JOIN member_dependent_information t2
    ON t1.MemberID = t2.MemberID
WHERE
  t1.Status = 1
GROUP BY
  t1.MemberID

【问题讨论】:

  • t1.Status = 1 来自哪里?
  • 它与一个活成员有关,即表中的另一个字段。我上面的例子应该包含整体想法

标签: mysql


【解决方案1】:

有时,解决问题的第一步是知道它的名称。在那之后,这只是一个谷歌搜索的问题。您尝试创建的内容称为数据透视表交叉表报告。这是一个解释如何创建pivot tables in MySQL 的链接。这是更深入的tutorial

更新:

现在您已经更新了问题,我对您要完成的工作有了更清晰的了解。我会根据 MySQL 的 GROUP_CONCAT 函数为您提供一个替代解决方案,它与您想要的类似但不是完全

select t1.FirstName, t1.LastName, group_concat(concat(t2.FirstName, ' ', t2.LastName))
from member_information as t1
left outer join member_dependent_information as t2 on t2.MemberID=t1.MemberID
group by t1.MemberID;

我已按如下方式验证了此查询。首先是设置:

create table member_information (
    MemberID int unsigned auto_increment primary key,
    FirstName varchar(32) not null,
    LastName varchar(32) not null
) engine=innodb;

create table member_dependent_information (
    MemberID int unsigned not null,
    FirstName varchar(32) not null,
    LastName varchar(32) not null,
    Type int unsigned not null,
    foreign key (MemberID) references member_information(MemberID)
) engine=innodb;

insert into member_information (MemberID, FirstName, LastName) values
(1, 'John', 'Harris'),
(2, 'Sarah', 'Thompson'),
(3, 'Zack', 'Lewis');

insert into member_dependent_information (MemberID, FirstName, LastName, `Type`) values
(1, 'Amy', 'Harris', 1),
(2, 'Bryan', 'Thompson', 1),
(2, 'Dewey', 'Thompson', 2),
(2, 'Tom', 'Thompson', 2),
(3, 'Harry', 'Lewis', 2),
(3, 'Minka', 'Lewis', 1);

现在是查询和结果:

mysql> select t1.FirstName, t1.LastName, group_concat(concat(t2.FirstName, ' ', t2.LastName))from member_information as t1
    -> left outer join member_dependent_information as t2 on t2.MemberID=t1.MemberID
    -> group by t1.MemberID;
+-----------+----------+------------------------------------------------------+
| FirstName | LastName | group_concat(concat(t2.FirstName, ' ', t2.LastName)) |
+-----------+----------+------------------------------------------------------+
| John      | Harris   | Amy Harris                                           | 
| Sarah     | Thompson | Bryan Thompson,Dewey Thompson,Tom Thompson           | 
| Zack      | Lewis    | Harry Lewis,Minka Lewis                              | 
+-----------+----------+------------------------------------------------------+
3 rows in set (0.00 sec)

【讨论】:

  • @Asaph - 首先,感谢您列出我正在寻找的内容。提供的 Wiki 并不真正适合我想要完成的工作,因为提供的示例与每一行中的项目具有一对一的关系。即使您要为“Bob”添加另一行,它也只会像可以添加测试分数一样求和,因此考试 1 的分数是 101+。我会继续研究你的其他教程。
  • @JM4:没问题。我认为您的问题可能是第一个教程中介绍的内容的细微变化。希望第二个能帮助您更准确地解决问题。如果没有,请告诉我。无论如何,我认为你最初的最大障碍是不知道谷歌的搜索词。所以我很高兴我对此有所帮助。
  • @Asaph - 我在提供的示例中阅读的每一页以及谷歌搜索提到的术语通常参考数字,这些数字被求和并用作单个值,这并不是我真正想要的去完成。我知道这可以通过 mysql 和 php 的组合相当容易地完成,但我试图完全避免使用 PHP,因为这将位于另一个人的机器上并且只能在本地运行。在提供的每个示例中,程序员都知道应该返回的列,而在我的示例中我不知道。每行可以有 0 个描述或 1000 个描述。
  • 最终,列创建将作为循环发生(即返回从表 3 中找到的行结果数,然后将 t3 中的每个描述作为结果集中的列列出
  • 再想一想——用 php 编程也不会那么简单,在筛选表 3 时的 foreach 循环将在行尾停止,然后可能会留下几列 关闭返回的数据。
【解决方案2】:

我不确定 OP 如何从 programIDStatus 转变为现在的样子,但我能得到的最接近的东西是(不需要数据透视表):

SELECT t1.MemberID,
    t1.FirstName,
    t1.LastName,
    concat(t2.FirstName, ' ', t2.LastName) as Spouse_Name,
    group_concat(concat(t3.FirstName, ' ', t3.LastName) ORDER BY t3.FirstName) as Children_names
FROM member_information t1
    LEFT JOIN member_dependent_information t2 ON (t1.MemberID=t2.MemberID AND t2.Type=1)
    LEFT JOIN member_dependent_information t3 ON (t1.MemberID=t3.MemberID and t3.Type=2)
GROUP BY MemberID;

产生:

+----------+------------+----------+------------ --+------------------+
|会员ID |名字 |姓氏 |配偶姓名 |孩子姓名 |
+----------+------------+----------+--------------- -+--------------+
| 1 |约翰 |哈里斯 |艾米哈里斯 |空 |
| 2 |莎拉 |汤普森 |布莱恩汤普森 |杜威汤普森,汤姆汤普森 |
| 3 |扎克 |刘易斯 |明卡刘易斯 |哈里·刘易斯 |
+----------+------------+----------+--------------- -+--------------+

使用任何编程语言都可以“轻松”将Children_names 提取到单独的列中。

【讨论】:

  • 每个问题,除非我被告知这是不可能的,否则不打算使用除 mysql 查询之外的任何外部程序。
  • @JM4:既然您标记了phppdo,我认为它们将被使用。
【解决方案3】:

这不是您正在寻找的,但它可能是朝着正确方向迈出的一步。

SELECT 
     Table1.memberIDs, 
     Table1.firstname, 
     Table1.lastnames, 
     Table2.programIDs, 
     Table3.description 
FROM 
     Table1, 
     Table2, 
     Table3 
WHERE 
     Table1.memberIDs = Table2.memberIDs AND 
     Table2.programIDs = Table3.programID

【讨论】:

  • 这个查询正是我想要避免的,因此也是我的问题。如果存在多个 programID(它们会),则此查询返回的结果集将返回多行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-26
  • 1970-01-01
  • 2010-12-18
  • 2017-11-15
  • 2011-06-17
  • 2016-09-21
  • 1970-01-01
相关资源
最近更新 更多