1

我正在尝试计算表中的行数,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

结果

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,但第一个日期不在其间EventToEventFrom因此不应计算在内。ID 4 出现了 3 次,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。我也尝试设置EventFromEventTo作为索引,但并没有太大的不同。这个查询是一个更大查询的一部分,所以我为主要部分设置了索引。

我也试过这个:

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 万行,但查询似乎仍然花费了不合理的长时间。有没有更好的方法来构建这个?

4

3 回答 3

5

SQL小提琴

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

结果

| 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 |
于 2013-09-11T15:37:10.603 回答
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;
于 2013-09-11T15:33:16.963 回答
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
于 2013-09-11T15:33:29.573 回答