1

events列の日付EventDateが別のテーブルで指定された 2 つの日付の間にあるテーブルの行を数えようとしています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 は に 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のインデックスとして設定しましたeventsEventFromandもインデックスとして設定してみ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 万行ありますが、それでもクエリに非常に長い時間がかかるようです。これを構造化するより良い方法はありますか?

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 joinon節に日付条件を入れます。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 に答える