0

我在完成 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

4 回答 4

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'
于 2012-06-27T09:50:23.333 回答
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_linetalb 一次,而不是多次。这应该意味着更低的读取、可能更低的 CPU 和通常更低的执行时间。

il.invID不利的一面是,如果需要,提取所有个人和il.name价值观会稍微复杂一些,并且不太直接。

于 2012-06-27T09:51:49.083 回答
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。因此,您可以简单地将它们相加以计算与给定表达式匹配的行数。换句话说,属于单个用户的连接中的所有行都被分组,匹配某个属性的那些行被计数,这些计数将决定在结果表中打印什么作为该用户的聚合值。

于 2012-06-27T09:53:11.543 回答
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

可能还有一些空值处理。

于 2012-06-27T09:58:00.190 回答