Возврат 0 в качестве результата SUM, если записи не найдены - PullRequest
0 голосов
/ 28 декабря 2018

Я пытаюсь суммировать калории действий в день для конкретного пользователя за последние 7 дней (фактический день - 7-й день).Существуют таблицы user и активность и таблица сопоставления user_activities.

Следующий пример предназначен для пользователя с id = 1;

Суммируйте калории каждый день в последние 7 дней (этот день7-й день) * /

SELECT  
    DATE(a.end_time), SUM(a.calories)
FROM
    activities a
JOIN
    user_activities uc ON uc.activity_id = a.id
WHERE
    uc.user_id = 1
    AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
GROUP BY 
    DATE(a.end_time) DESC

Этот запрос возвращает этот набор результатов:

2018-12-28   9600
2018-12-27   1200
2018-12-26   1200
2018-12-25   1200
2018-12-24   4800
2018-12-22   1200

Это правильно, но теперь моя проблема в том, как вы можете видеть в списке12-23-2018 не числится в списке, так как в эту дату нет действийТеперь я хочу отобразить

2018-12-23   0

вместо ничего.

Как получить желаемый результат?

Спасибо за вашу помощь

Я тожепробовал с IFNULL и COALESCE, но пока не повезло

Суммируйте калории каждый день в последние 7 дней (этот день 7-й день) * /

SELECT  
    DATE(a.end_time), SUM(a.calories)
FROM
    activities a
JOIN 
    user_activities uc ON uc.activity_id = a.id
WHERE 
    uc.user_id = 1
    AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
GROUP BY
    DATE(a.end_time) DESC

Результат:

2018-12-28   9600
2018-12-27   1200
2018-12-26   1200
2018-12-25   1200
2018-12-24   4800
2018-12-22   1200

Ожидаемый результат:

2018-12-28   9600
2018-12-27   1200
2018-12-26   1200
2018-12-25   1200
2018-12-24   4800
2018-12-23      0
2018-12-22   1200

Activities Таблица:

enter image description here

Ответы [ 4 ]

0 голосов
/ 28 декабря 2018

Этот запрос должен к хитрости:

  • CTE динамически генерирует диапазон дат (это будет примерно на 300 лет вперед)
  • результат равен LEFT JOIN edс таблицами activities и user_activities
  • функция COALESCE превращает пустые SUM s в 0 значения

Запрос:

WITH v AS (
    SELECT * FROM 
        (SELECT adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) selected_date FROM
        (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t0,
        (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1,
        (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2,
        (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3,
        (SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t4) v
    WHERE selected_date BETWEEN CURRENT_DATE - INTERVAL 6 DAY AND CURRENT_DATE
)
SELECT v.selected_date, COALESCE(SUM(a.calories), 0)
FROM 
    v
    LEFT JOIN activities a on DATE(a.end_time) = v.selected_date
    LEFT JOIN user_activities uc ON uc.activity_id = a.id AND uc.user_id = 1
GROUP BY DATE(a.end_time) DESC
ORDER BY v.selected_date
0 голосов
/ 28 декабря 2018

Если есть вероятность, что в таблице ваших действий нет активности в определенный день, то хитрость fa06 не сработает.Простой способ охватить этот случай - добавить несколько нулевых записей до того, как вы внесете сумму:

SELECT DATE(d), SUM(c)
FROM (
  SELECT  a.end_time as d, a.calories as c
  FROM activities a
  JOIN user_activities uc ON uc.activity_id = a.id
  WHERE uc.user_id = 1
  AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
  UNION ALL
  SELECT CURRENT_DATE, 0
  UNION ALL
  SELECT CURRENT_DATE - INTERVAL 1 DAY, 0
  UNION ALL
  SELECT CURRENT_DATE - INTERVAL 2 DAY, 0
  UNION ALL
  SELECT CURRENT_DATE - INTERVAL 3 DAY, 0
  UNION ALL
  SELECT CURRENT_DATE - INTERVAL 4 DAY, 0
  UNION ALL
  SELECT CURRENT_DATE - INTERVAL 5 DAY, 0
  UNION ALL
  SELECT CURRENT_DATE - INTERVAL 6 DAY, 0
) z
GROUP BY DATE(d)

Метод fa06 основан на том, что в таблице операций каждый день по одной записи.Это верный способ решения проблемы, но вы не знаете, какие данные содержат эти таблицы (подсказка: при публикации вопроса о БД включайте образцы данных из каждой таблицы)

С помощью этого метода мы делаемнаш поиск как обычно, но мы также генерируем 7 фальшивых строк с датами за последние 7 дней и 0 калорий.При добавлении к реальному количеству калорий они не содержат жира;) и когда нет данных за конкретный день, они автономно предоставляют 0

. Если вы хотите больше дней, рассмотрите возможность перехода к шаблону генерации строк.,В MySQL нет таких генераторов строк, как в других БД, но самый простой способ - создать переменную, инициализировать ее с 0, затем увеличивать и использовать ее для каждой строки, возвращаемой из таблицы, содержащей не менее 30 строк:

SELECT CURRENT_DATE - INTERVAL (@row := @row + 1) DAY as dt, 0 as cal
FROM activities t, (SELECT @row := -1) r
LIMIT 30

Теория, лежащая в основе этого: таблица содержит не менее 30 строк, переменная @row имеет значение -1 и существует для запроса в сеансе.Когда строки извлекаются и возвращаются, @row увеличивается, а затем возвращается (так что это 0, 1, 2 ..), и это увеличивающееся число используется для вычитания 0, 1, 2 и т. Д. Выходных текущих данных, что дает нампоследовательность дат за последние 30 дней

SELECT DATE(d), SUM(c)
FROM (
  SELECT  a.end_time as d, a.calories as c
  FROM activities a
  JOIN user_activities uc ON uc.activity_id = a.id
  WHERE uc.user_id = 1
  AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 29 DAY
  UNION ALL

  SELECT CURRENT_DATE - INTERVAL (@row := @row + 1) DAY as dt, 0 as cal
  FROM activities t, (SELECT @row := -1) r
  WHERE @row < 30
) z
GROUP BY DATE(d)

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

Отладка:

Запустите каждый из этих запросов по отдельности.Я не знаю, сколько строк это будет производить:

  SELECT  a.end_time as d, a.calories as c
  FROM activities a
  JOIN user_activities uc ON uc.activity_id = a.id
  WHERE uc.user_id = 1
  AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 29 DAY

И этот должен произвести 30 строк.Если этого не произойдет, это будет потому, что вы не использовали таблицу с хотя бы 30 строками:

  SELECT CURRENT_DATE - INTERVAL (@row := @row + 1) DAY as dt, 0 as cal
  FROM activities t, (SELECT @row := -1) r
  LIMIT 30

Редактировать:

Исправлена ​​ошибка с этим - LIMIT применялся послеСоюз;это дало нежелательные результаты

0 голосов
/ 28 декабря 2018

Я пытаюсь сделать это с моей стороны и просто обновил SUM(a.calories) до IF(SUM(a.calories) IS NULL, 0, SUM(a.calories))

Здесь вы можете попробовать ...

SELECT  DATE(a.end_time), IF(SUM(a.calories) IS NULL, 0, SUM(a.calories))
  FROM activities a
    JOIN user_activities uc ON uc.activity_id = a.id
  WHERE uc.user_id = 1
    AND
     DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
  GROUP BY DATE(a.end_time) DESC
0 голосов
/ 28 декабря 2018

Вы можете попробовать ниже - используя левое соединение

SELECT  DATE(a.end_time), SUM(a.calories)
FROM activities a
left JOIN user_activities uc ON uc.activity_id = a.id
Where uc.user_id = 1 AND DATE(a.end_time) >= CURRENT_DATE - INTERVAL 6 DAY
GROUP BY DATE(a.end_time) order by DATE(a.end_time) DESC
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...