Использование подзапросов
Один из способов решить эту проблему - использовать подзапросы . LEFT JOIN
создает новый «результат» для каждого совпадения в правой таблице, поэтому использование двух ЛЕВЫХ СОЕДИНЕНИЙ создает больше строк, чем вы хотите. Вы можете просто выбрать нужное значение, но это может быть медленным:
SELECT ta.id,
(SELECT SUM(total_sold) as total_sold
FROM table_b
WHERE date_sold BETWEEN ADDDATE(NOW(), INTERVAL -1 WEEK) AND NOW()
AND id=ta.id) as total_sold_this_week,
(SELECT SUM(total_sold) as total_sold
FROM table_b
WHERE date_sold BETWEEN ADDDATE(NOW(), INTERVAL -1 MONTH) AND NOW()
AND id = ta.id) as total_sold_this_month
FROM table_a ta;
Результат:
+----+----------------------+-----------------------+
| id | total_sold_this_week | total_sold_this_month |
+----+----------------------+-----------------------+
| 1 | 3 | 7 |
| 2 | 4 | 4 |
| 3 | NULL | NULL |
+----+----------------------+-----------------------+
3 rows in set (0.04 sec)
Использование SUM (CASE ...)
Этот метод не использует подзапросы (и, скорее всего, будет быстрее для больших наборов данных). Мы хотим объединить table_a и table_b один раз, используя наш «самый большой» диапазон дат, а затем использовать SUM()
на основе CASE
для вычисления «меньшего диапазона».
SELECT ta.*,
SUM(total_sold) as total_sold_last_month,
SUM(CASE
WHEN date_sold BETWEEN NOW() - INTERVAL 1 WEEK AND NOW()
THEN total_sold
ELSE 0
END) as total_sold_last_week
FROM table_a AS ta
LEFT JOIN table_b AS tb
ON ta.id=tb.id AND tb.date_sold BETWEEN ADDDATE(NOW(),INTERVAL -1 MONTH) AND NOW()
GROUP BY ta.id;
Возвращает почти тот же набор результатов, что и в примере подзапроса:
+----+-----------------------+----------------------+
| id | total_sold_last_month | total_sold_last_week |
+----+-----------------------+----------------------+
| 1 | 7 | 3 |
| 2 | 4 | 4 |
| 3 | NULL | 0 |
+----+-----------------------+----------------------+
3 rows in set (0.00 sec)
Единственная разница - 0
вместо NULL
. Вы можете суммировать столько диапазонов дат, сколько захотите, используя этот метод, но все же, вероятно, все же лучше ограничить строки, возвращаемые самым большим диапазоном в предложении ON
.
Просто чтобы показать, как это работает: удаление вызовов GROUP BY
и SUM()
и добавление date_sold
к SELECT возвращает это:
+----+------------+-----------------------+----------------------+
| id | date_sold | total_sold_last_month | total_sold_last_week |
+----+------------+-----------------------+----------------------+
| 1 | 2010-04-30 | 2 | 2 |
| 1 | 2010-04-24 | 2 | 0 |
| 1 | 2010-04-24 | 2 | 0 |
| 1 | 2010-05-03 | 1 | 1 |
| 2 | 2010-05-03 | 4 | 4 |
| 3 | NULL | NULL | 0 |
+----+------------+-----------------------+----------------------+
6 rows in set (0.00 sec)
Теперь, когда вы GROUP BY id
и SUM()
в двух столбцах total_sold у вас есть результаты!
Старый совет
До того, как вы добавили два разных диапазона дат в микс, вы могли бы использовать GROUP BY
для группировки, используя идентификатор таблицы в table1, и агрегатную функцию SUM()
для сложите возвращенные строки.
SELECT ta.id, SUM(tb.total_sold) as total_sold_this_week
FROM table_a as ta
LEFT JOIN table_b as tb
ON ta.id=tb.id AND tb.date_sold BETWEEN ADDDATE(NOW(),INTERVAL -3 WEEK) AND NOW()
GROUP BY ta.id
+----+----------------------+
| id | total_sold_this_week |
+----+----------------------+
| 1 | 7 |
| 2 | 4 |
| 3 | NULL |
+----+----------------------+
3 rows in set (0.00 sec)
Данные испытаний
NOW()
- 2010-05-03
mysql> select * from table_a; select * from table_b;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
3 rows in set (0.00 sec)
+----+------------+------------+
| id | date_sold | total_sold |
+----+------------+------------+
| 1 | 2010-04-24 | 2 |
| 1 | 2010-04-24 | 2 |
| 1 | 2010-04-30 | 2 |
| 1 | 2010-05-03 | 1 |
| 2 | 2010-05-03 | 4 |
+----+------------+------------+
5 rows in set (0.00 sec)