MySQL - 合并表行(group by不起作用)

时间:2012-06-27 09:43:04

标签: mysql sql

我在完成MySQL查询时遇到了一些麻烦。想象一下,我将表格票证,发票行和用户组合在一起。每张票都有一个或多个发票行,每个用户可以有一张或多张票。

我正在尝试创建一个可用于创建名称徽章的查询。对于这个徽章,我需要知道该人注册的名称和项目。

我创建了以下MySQL查询

SELECT u.firstName, u.lastName, il.invID, il.name, 
CASE 
  WHEN il.name = 'Conference Dinner' 
  THEN 'Diner'
END AS 'conference_dinner',

CASE 
  WHEN il.name = 'Regular Conference Fee' THEN 'Conference'
  WHEN il.name = 'Conference Fee for Phd. Students'  THEN 'Conference'
END AS 'conference',

CASE
  WHEN il.name = 'Pre-Conference Fee' THEN 'Pre-Conference'
END AS 'pre_conference',

FROM invoice_line il, events_tickets et, users u
WHERE il.invID = et.invID
AND et.userID = u.ID

查询几乎没问题,但它为表中三条发票行(=三项)三条线的用户生成,我希望这三行合并为一行。用户ID上的Group By将产生一行,但是创建的列不会合并到一行中,只会显示其中一行。

我可能使用了错误的方法。但它应该产生一个这样的表:

firstName | lastName | conference_diner | conference | pre_conference |
----------------------------------------------------------------------
John      | Doe      | Diner            | Conference |                |
Jane      | Norman   |                  | Conference | Pre-Conference | 
Martijn   | Thomas   |                  | Conference |                |
Pete      | Johns    |                  |            | Pre-Conference |

目前导致:

firstName | lastName | conference_diner | conference | pre_conference |
----------------------------------------------------------------------
John      | Doe      | Diner            |            |                |
John      | Doe      |                  | Conference |                |
Jane      | Norman   |                  | Conference |                |
Jane      | Norman   |                  |            | Pre-Conference |  
Martijn   | Thomas   |                  | Conference |                |
Pete      | Johns    |                  |            | Pre-Conference |

提前致谢

4 个答案:

答案 0 :(得分:2)

这样的事情:

SELECT u.firstName, u.lastName, et.invID,
CASE 
  WHEN il_d.name IS NULL THEN '' ELSE 'Diner'
END AS 'conference_dinner',

CASE 
  WHEN il_c.name IS NULL THEN '' ELSE 'Conference'
END AS 'conference',

CASE
  WHEN il_p.name IS NULL THEN '' ELSE 'Pre-Conference'
END AS 'pre_conference'
FROM events_tickets et
INNER JOIN users u ON et.userID = u.ID
LEFT JOIN invoice_line il_d ON il_d.invID = et.invID AND il_d.name = 'Conference Dinner'
LEFT JOIN invoice_line il_c ON il_c.invID = et.invID AND il_c.name IN ('Regular Conference Fee', 'Conference Fee for Phd. Students')
LEFT JOIN invoice_line il_p ON il_p.invID = et.invID AND il_p.name = 'Pre-Conference Fee'

答案 1 :(得分:1)

由于您尚未包含源数据,我将假设您的最终结果中的每一列与输入数据中的一行相关。

这意味着您想使用GROUP BY ...

SELECT
  u.firstName, u.lastName, il.invID, il.name, 
  MAX(CASE
    WHEN il.name = 'Conference Dinner'                 THEN 'Diner'
  END) AS 'conference_dinner',
  MAX(CASE
    WHEN il.name = 'Regular Conference Fee'            THEN 'Conference'
    WHEN il.name = 'Conference Fee for Phd. Students'  THEN 'Conference'
  END) AS 'conference',    
  MAX(CASE
    WHEN il.name = 'Pre-Conference Fee'                THEN 'Pre-Conference'
  END) AS 'pre_conference'

FROM
  invoice_line il, events_tickets et, users u
WHERE
  il.invID = et.invID AND et.userID = u.ID
GROUP BY
  u.firstName, u.lastName

但是,我必须从il.invID, il.name,中移除SELECT。这是因为我推断他们可以有不同的价值观。在哪种情况下,您希望在汇总结果中显示哪个值?

修改

这比多个LEFT JOIN版本更有优势,因为它只扫描invoice_line talb eonce,而不是多次。这个应该意味着更低的读取,可能更低的CPU,并且通常更低的执行时间。

缺点是它稍微复杂一点,如果需要,可以不那么直接地提取所有单独的il.invIDil.name值。

答案 2 :(得分:1)

你可以尝试这些方法:

SELECT u.firstName, u.lastName, il.invID, il.name,
IF(SUM(il.name = 'Conference Dinner') > 0,
    'Diner', '') AS 'conference_dinner',
IF(SUM(il.name IN ('Regular Conference Fee',
                   'Conference Fee for Phd. Students')) > 0,
    'Conference', '') AS 'conference',
IF(SUM(il.name = 'Pre-Conference Fee') > 0,
    'Pre-Conference', '') AS 'pre_conference'
FROM invoice_line il, events_tickets et, users u
WHERE il.invID = et.invID
AND et.userID = u.ID
GROUP BY u.ID

mysql中的比较结果为数字,0表示 false ,1表示 true 。因此,您可以简单地对这些进行求和,以计算与给定表达式匹配的行。换句话说,属于单个用户的联接中的所有行都被分组,对与特定属性匹配的那些行进行计数,这些计数将决定在结果表中打印什么作为该用户的聚合值。

答案 3 :(得分:0)

在event_tickets表中添加一些自连接

SELECT u.firstName, u.lastName, il.invID, il.name, 
CASE 
  WHEN il.name = 'Conference Dinner' 
  THEN 'Diner'
END AS 'conference_dinner',

CASE 
  WHEN il.name = 'Regular Conference Fee' THEN 'Conference'
  WHEN il.name = 'Conference Fee for Phd. Students'  THEN 'Conference'
END AS 'conference',

CASE
  WHEN il.name = 'Pre-Conference Fee' THEN 'Pre-Conference'
END AS 'pre_conference',

FROM invoice_line il, events_tickets et1, events_tickets et2, event_tickets et3, users u
WHERE il.invID = et.invID
AND et1.userID = u.ID
AND et2.userID = u.ID
AND et3.userID = u.ID

但是还要在连接中包含一些内容,以确保您不会获得两次晚餐,例如,如果et.name是指定'Diner'与'Conferece'等属性,那么您将需要

AND et1.name > et2.Name
AND et.name > et3.name

可能还有一些空处理。