我正在尝试计算表events
中的行,其中列EventDate
中的日期出现在另一个表customers
中给出的两个日期之间。
客户
ID EventFrom EventTo
-- ---------- -----------
1 2011-01-01 2012-01-01
2 2012-12-10 2013-12-10
3 2010-05-01 2011-05-01
4 2011-01-01 2012-01-01
5 2012-07-30 2013-07-30
6 2011-06-21 2012-06-21
7 2011-06-22 2012-06-22
8 2010-02-19 2011-02-19
活动
ID EventDate
-- ----------
2 1999-01-01
2 2012-12-12
2 2012-12-13
3 1900-01-12
4 2011-02-10
4 2011-02-11
4 2011-02-12
RESULT
ID EventFrom EventTo Events
-- ---------- ----------- ------
1 2011-01-01 2012-01-01 0
2 2012-12-10 2013-12-10 2
3 2010-05-01 2011-05-01 0
4 2011-01-01 2012-01-01 3
5 2012-07-30 2013-07-30 0
6 2011-06-21 2012-06-21 0
7 2011-06-22 2012-06-22 0
8 2010-02-19 2011-02-19 0
ID {2}在events
中出现两次,但第一个日期不在EventTo
和EventFrom
之间,因此不应计算在内。 ID 4在events
中出现三次,并且都在正确的范围内。
我可以做到,但我最终得到了一个非常慢的嵌套连接。
SELECT customers.ID
, customers.EventFrom
, customers.EventTo
, IFNULL(e.Events, 0) AS 'Events'
FROM customers
LEFT JOIN (
SELECT events.ID, COUNT(events.ID) AS 'Events'
FROM events
INNER JOIN customers ON customers.ID = events.ID
AND events.EventDate BETWEEN customers.EventFrom AND customers.EventTo
GROUP BY events.ID
) e ON e.ID = customers.ID
我已将EventDate
设置为events
中的索引。我尝试将EventFrom
和EventTo
设置为索引,但它没有产生很大的不同。此查询是较大查询的一部分,因此我为主要部分设置了索引。
我也试过这个:
SELECT customers.ID
, customers.EventFrom
, customers.EventTo
, SUM(IF(events.EventDate BETWEEN customers.EventFrom AND customers.EventTo), 1, 0) AS 'Events'
FROM customers
LEFT JOIN events ON events.ID = customers.ID
这也非常慢。 customers
有大约150万行,但查询似乎仍然花费了不合理的长时间。有没有更好的结构方式?
答案 0 :(得分:5)
MySQL 5.5.32架构设置:
CREATE TABLE CUSTOMERS
(`ID` varchar(2), `EventFrom` varchar(10), `EventTo` varchar(11))
;
INSERT INTO CUSTOMERS
(`ID`, `EventFrom`, `EventTo`)
VALUES
('1', '2011-01-01', '2012-01-01'),
('2', '2012-12-10', '2013-12-10'),
('3', '2010-05-01', '2011-05-01'),
('4', '2011-01-01', '2012-01-01'),
('5', '2012-07-30', '2013-07-30'),
('6', '2011-06-21', '2012-06-21'),
('7', '2011-06-22', '2012-06-22'),
('8', '2010-02-19', '2011-02-19')
;
CREATE TABLE EVENTS
(`ID` int, `EventDate` datetime)
;
INSERT INTO EVENTS
(`ID`, `EventDate`)
VALUES
(2, '1999-01-01 00:00:00'),
(2, '2012-12-12 00:00:00'),
(2, '2012-12-13 00:00:00'),
(3, '1900-01-12 00:00:00'),
(4, '2011-02-10 00:00:00'),
(4, '2011-02-11 00:00:00'),
(4, '2011-02-12 00:00:00')
;
查询1 :
SELECT c.Id, c.EventFrom, c.EventTo, COUNT(e.ID)
FROM CUSTOMERS c
LEFT JOIN EVENTS e ON e.ID = c.ID AND
e.EventDate BETWEEN c.EventFrom AND c.EventTo
GROUP BY c.Id, c.EventFrom, c.EventTo
<强> Results 强>:
| ID | EVENTFROM | EVENTTO | COUNT(E.ID) |
|----|------------|------------|-------------|
| 1 | 2011-01-01 | 2012-01-01 | 0 |
| 2 | 2012-12-10 | 2013-12-10 | 2 |
| 3 | 2010-05-01 | 2011-05-01 | 0 |
| 4 | 2011-01-01 | 2012-01-01 | 3 |
| 5 | 2012-07-30 | 2013-07-30 | 0 |
| 6 | 2011-06-21 | 2012-06-21 | 0 |
| 7 | 2011-06-22 | 2012-06-22 | 0 |
| 8 | 2010-02-19 | 2011-02-19 | 0 |
答案 1 :(得分:1)
用户left join
。将日期条件放在on
子句中。然后使用count(e.ID)
计算表中的匹配项(计算非NULL值):
SELECT c.ID, c.EventFrom, c.EventTo,
COUNT(e.ID) as "Events"
FROM customers c LEFT JOIN
events e
ON e.ID = c.ID and
e.EventDate BETWEEN c.EventFrom AND c.EventTo
GROUP BY c.ID, c.EventFrom, c.EventTo;
答案 2 :(得分:1)
我宁愿做
select
c.Id,
c.EventFrom,
c.EventTo
COUNT(e.ID)
FROM customers c
LEFT JOIN events e on e.ID = c.ID and e.EvenDate BETWEEN c.EventFrom and c.EventTo
GROUP BY c.Id, c.EventFrom, c.EventTo