Сложное соединение - с учетом диапазонов дат и суммы

StackOverflow https://stackoverflow.com/questions/2759270

  •  02-10-2019
  •  | 
  •  

Вопрос

У меня есть две таблицы, которые мне нужно присоединиться ... Я хочу присоединиться к Table1 и Table2 на «ID» - однако в таблице два идентификатора не является уникальным. Я хочу, чтобы только одно значение возвращалось для таблицы второй, и это значение представляет собой сумму столбца под названием «total_sold» - в пределах указанного диапазона дат (скажем, один месяц), однако я хочу одновременно более одного диапазона дат ...

SELECT ta.id, sum(tb.total_sold) as total_sold_this_week, sum(tc.total_sold) as total_sold_this_month
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 WEEK) AND NOW()
LEFT JOIN table_b as tc ON ta.id=tc.id AND tc.date_sold BETWEEN ADDDATE(NOW(),INTERVAL -1 MONTH) AND NOW()
GROUP BY ta.id

Это работает, но не подводит итог рядов - возвращая только одну строку для каждого идентификатора ... Как получить сумму из таблицы B вместо только одной строки ??? Пожалуйста, критикуйте, может ли формат вопроса использовать больше работы - я могу переписать и предоставить образцы данных, если это необходимо - это тривиальная версия гораздо большей проблемы.

-Спасибо

Это было полезно?

Решение

Использование подборов

Одним из способов решить это было бы использовать подростки. 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)

Использование суммы (дело ...)

Этот метод не использует подводы (и, вероятно, будет быстрее в более крупных наборах данных). Мы хотим объединить 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 На выбор возвращает это:

+----+------------+-----------------------+----------------------+
| 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 группировать использование идентификатора таблицы в таблице 1 и 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)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top