Я пытаюсь построить запрос SQLite, который будет собирать статистику из одной таблицы.

Таблица содержит своего рода журнал с несколькими записями в день. Мне нужно получить отдельную строку для каждого дня в параметрах поиска, а затем скомпилировать итоги строк за эти даты с определенными логическими значениями.

Вот запрос, который я имею до сих пор:

SELECT DATE(DateTime) AS SearchDate,
     (SELECT COUNT() AS Total
                FROM CallRecords
                WHERE DATE(DateTime)
                BETWEEN '2017-08-27' AND '2017-09-02'
                GROUP BY DATE(DateTime)
                ORDER BY Total DESC) AS Total,
    (SELECT COUNT() AS Total
                FROM CallRecords
                WHERE NoMarket = 1
                AND DATE(DateTime)
                BETWEEN '2017-08-27' AND '2017-09-02'
                GROUP BY DATE(DateTime)
                ORDER BY Total DESC) AS NoMarkets,
    (SELECT COUNT() AS Total
                FROM CallRecords
                WHERE Complaint = 1
                AND DATE(DateTime)
                BETWEEN '2017-08-27' AND '2017-09-02'
                GROUP BY DATE(DateTime)
                ORDER BY Total DESC) AS Complaints,
    (SELECT COUNT() AS Total
                FROM CallRecords
                WHERE Voicemail = 1
                AND DATE(DateTime)
                BETWEEN '2017-08-27' AND '2017-09-02'
                GROUP BY DATE(DateTime)
                ORDER BY Total DESC) AS Voicemails
FROM CallRecords
WHERE DATE(DateTime) BETWEEN '2017-08-27' AND '2017-09-02'
GROUP BY SearchDate

И вывод:

8/28/2017   175 27      11
8/29/2017   175 27      11
8/30/2017   175 27      11
8/31/2017   175 27      11
9/1/2017    175 27      11

Как видите, он правильно получает каждую отдельную дату, но итоги по столбцам неверны.

Очевидно, я что-то упустил в своем запросе, но я не уверен, где. Есть ли лучший способ выполнить этот запрос?

РЕДАКТИРОВАТЬ: Я рассмотрел несколько других вопросов с почти одинаковыми названиями здесь, но я не нашел ничего похожего на то, что я ищу. Большинство кажется гораздо более сложным, чем то, что я пытаюсь сделать.

3
Zephyr 7 Сен 2017 в 20:59

3 ответа

Лучший ответ

Похоже, у вас в таблице CallRecords беспорядок столбцов с именами вроде Complaint и Voicemail, каждое из которых классифицирует вызов.

Похоже, что эти столбцы имеют значение 1, когда они актуальны.

Так что этот запрос, вероятно, должен помочь вам.

SELECT DATE(DateTime) AS SearchDate,
       COUNT(*) AS Total,
       SUM(NoMarket = 1) AS NoMarkets,
       SUM(Complaint = 1) AS Complaints,
       SUM(Voicemail = 1) AS Voicemails
  FROM CallRecords
 WHERE DateTime >=  '2017-08-27'
   AND DateTime <   '2017-09-02' + INTERVAL 1 DAY
 GROUP BY DATE(DateTime)

Почему это работает? Потому что в MySQL логическое выражение типа Voicemail = 1 имеет значение 1, когда оно истинно, и 0, когда оно ложно. Вы можете суммировать эти значения довольно хорошо.

Почему это быстрее, чем у вас есть? Потому что DATE(DateTime) BETWEEN this AND that не может использовать индекс DateTime.

Почему это правильно для конца вашего диапазона дат? Потому что DateTime < '2017-09-02' + INTERVAL 1 DAY извлекает все записи вплоть до, но не включая полночь, дня после вашего диапазона дат.

Если вы используете Sqlite, вам нужно AND DateTime < date('2017-09-02', '+1 day'). Материал + INTERVAL 1 DAY там немного другой.

5
O. Jones 8 Сен 2017 в 19:58
SELECT DATE(DateTime) AS SearchDate, Total, NoMarkets, Complaints, Voicemails FROM
 (SELECT COUNT() AS Total FROM CallRecords) CR
 JOIN
(SELECT COUNT() AS NoMarkets FROM CallRecords WHERE NoMarket = 1) NM
 ON CR.DateTime = NM.DateTime
 JOIN
(SELECT COUNT() AS Complaints FROM CallRecords WHERE Complaint = 1) C
 ON NM.DateTime = C.DateTime
 JOIN
(SELECT COUNT() AS Voicemails FROM CallRecords WHERE Voicemail = 1) VM
 ON C.DateTime = VM.DateTime
 JOIN CallRecords CLR ON VM.DateTime=CLR.DateTime WHERE DATE(CLR.DateTime) >= '2017-08-27' AND DATE(CLR.DateTime) <= '2017-09-02'GROUP BY SearchDate;

Это может выводить правильно.

0
Jignesh M. Khatri 7 Сен 2017 в 18:18

Вы можете делать так, хотя я написал на SQL-сервере

SELECT DATE(DateTime) AS SearchDate,
    COUNT() AS TOTAL,
    SUM(CASE WHEN NoMarket = 1 THEN 1 ELSE 0 END) AS NoMarkets,
    SUM(CASE WHEN Complaint = 1 THEN 1 ELSE 0 END) AS Complaints,
    SUM(CASE WHEN Voicemail = 1 THEN 1 ELSE 0 END) AS Voicemails
FROM CallRecords
WHERE DATE(DateTime) BETWEEN '2017-08-27' AND '2017-09-02'
GROUP BY SearchDate
1
Bijan Ghasemi 7 Сен 2017 в 18:18