我有3张桌子:
CREATE TABLE `ticket` (
`tid` int(11) NOT NULL AUTO_INCREMENT,
`sid` varchar(50) NOT NULL,
`open_date` datetime NOT NULL,
PRIMARY KEY (`tid`),
KEY `sid` (`sid`,`open_date`),
KEY `open_date` (`open_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `ticket_reply` (
`rid` int(11) NOT NULL AUTO_INCREMENT,
`tid` int(11) NOT NULL,
`reply_date` datetime NOT NULL,
PRIMARY KEY (`rid`),
KEY `tid` (`tid`,`reply_date`),
KEY `reply_date` (`reply_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `subscription` (
`sid` varchar(50) NOT NULL,
`response_time` int(11) NOT NULL DEFAULT '24',
PRIMARY KEY (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
我正在尝试获取第一张故障单回复的响应时间总和,从故障单打开时将其分组并按DAYNAME分组(也可能是MONTH)。目前我有这个SQL:
SELECT
t.tid,
DAYNAME(t.open_date) AS day_opened,
SUM(TIMESTAMPDIFF(MINUTE, t.open_date, tr.reply_date)) AS num_min,
SUM(s.response_time * 60) AS response_time_min
FROM ticket t
INNER JOIN ticket_reply tr ON tr.tid = t.tid
INNER JOIN subscription s ON s.sid = t.sid
GROUP BY
t.tid #group by tid as ticket_reply may return many
ORDER BY t.open_date DESC;
所以我的第一个挑战是获得第一个由GROUP BY解决的ticket_reply行,我试图在连接中获得一个子查询,但它仍然为每个ticket_reply行返回一行。
所以现在我想开始按DAYNAME分组,也许MONTH,但如果我将它添加到GROUP BY,它就不会分组:
GROUP BY
t.tid,
DAYNAME(t.open_date)
在tid之前尝试了DAYNAME,但这没有任何区别。
所以我有几个问题,是否有更好的方法来获取ticket_reply中的第一行然后按DAYNAME分组?我有一种感觉,让子查询中的第一行可以修复分组。
答案 0 :(得分:0)
它是分组,但是因为t.tid
子句中有GROUP BY
,而tid
列中的ticket
列是唯一的,所以来自{{1}的多行不会崩溃,每个都会在自己的行上。
您不清楚要返回的结果。
(SELECT列表中的ticket
表达式看起来有点奇怪,因为您可以匹配SUM(s.response_time)
中的多行。)
鉴于您现有的陈述,看起来您可能希望使用内联视图来返回最早的"每个票证ticket_reply
,代替对reply_date
表的引用。
ticket_reply
(不幸的是,实现内联视图(填充和访问中间"派生表")可能是性能问题的根源。)
作为另一种选择,您可以考虑在 JOIN /*ticket_reply*/
( SELECT r.tid
, MIN(r.reply_date) AS reply_date
FROM ticket_reply r
GROUP BY r.tid
) tr ON tr.tid = t.tid
列表中使用相关子查询,而不是执行JOIN操作。也就是说,代替SELECT
的引用,您可以执行以下操作:
tr.reply_date
并删除JOIN到 (SELECT MIN(r.reply_date) FROM ticket_reply r WHERE r.tid = t.tid)
表。
但是,重复执行该子查询(对于返回的每一行一次),也可能是大型集的性能问题。
但是"大"问题是,您是否需要为匹配的ticket_reply
的每次匹配添加s.response_time
(正如您当前的查询所做的那样),或者您是否只需要为每个ticket_reply
添加一次s.response_time
{1}}?
也就是说,如果给定的ticket
有三ticket_reply
,我们是否需要"三倍"我们添加到行的ticket
的值?
如果您需要在每个`ticket_reply的总数中包含response_time
,那么:
response_time
如果您只需要在每个SELECT DAYNAME(t.open_date) AS day_opened
, SUM(TIMESTAMPDIFF(MINUTE, t.open_date, tr.reply_date)) AS num_min
, SUM(s.response_time) * 60 * tr.cnt_replies AS response_time_min
FROM ticket t
JOIN ( SELECT r.tid
, MIN(r.reply_date) AS reply_date
, COUNT(1) AS cnt_replies
FROM ticket_reply r
GROUP BY r.tid
) tr
ON tr.tid = t.tid
JOIN subscription s
ON s.sid = t.sid
GROUP
BY day_opened
的总计中包含response_time
,请删除对ticket
的引用:
cnt_replies
到SELECT DAYNAME(t.open_date) AS day_opened
, SUM(TIMESTAMPDIFF(MINUTE, t.open_date, tr.reply_date)) AS num_min
, SUM(s.response_time) * 60 AS response_time_min
FROM ticket t
JOIN ( SELECT r.tid
, MIN(r.reply_date) AS reply_date
FROM ticket_reply r
GROUP BY r.tid
) tr
ON tr.tid = t.tid
JOIN subscription s
ON s.sid = t.sid
GROUP
BY day_opened
个月,只需更改SELECT列表中的第一个表达式,以及GROUP BY子句中的引用。