Создание сводного обзора из полей из нескольких таблиц - PullRequest
0 голосов
/ 11 декабря 2018

Я пытаюсь написать запрос на выборку для создания представления в MySQL.Каждая строка в представлении должна отображать еженедельную сводку (sum, avg) для пользовательских значений, собранных из нескольких таблиц.Таблицы похожи друг на друга, но не идентичны.Представление должно включать строки также в случае, если другая таблица не имеет значений для этой недели.Примерно так:

| week_year | sum1 | avg1 | sum2 | user_id |
| --------- | ---- | ---- | ---- | ------- |
| 201840    |      |      | 3    | 1       |
| 201844    | 45   | 55   |      | 1       |
| 201845    | 55   | 65   |      | 1       |
| 201849    | 65   | 75   |      | 1       |
| 201849    | 75   | 85   | 3    | 2       |

Таблицы (упрощенные) выглядят следующим образом:

CREATE TABLE IF NOT EXISTS `t1` (
  `user_id` INT NOT NULL AUTO_INCREMENT,
  `date` DATE NOT NULL,
  `value1` int(3) NOT NULL,
  `value2` int(3) NOT NULL,
  PRIMARY KEY (`user_id`,`date`)
) DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `t2` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `date` DATE NOT NULL,
  `value3` int(3) NOT NULL,
  PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `t3` (
  `t3_id` INT NOT NULL,
  `user_id` INT NOT NULL
) DEFAULT CHARSET=utf8;

Мое текущее решение не кажется разумным, и я не уверен, как оно будетвыполнить в случае тысяч строк:

select ifnull(yearweek(q1.date1), yearweek(q1.date2)) as week_year,
       sum(value1)                             as sum1,
       avg(value2)                              as avg1,
       sum(value3)                                   as sum2,
       q1.user_id
from (select t2.date as date2,
             t1.date as date1,
             ifnull(t3.user_id, t1.user_id) as user_id,
             t1.value1,
             t1.value2,
             t2.value3
      from t2
             join t3 on t3.t3_id=t2.id
             left join t1 on yearweek(t1.date) = yearweek(t2.date) and t1.user_id = t3.user_id
      union
      select t2.date as date2,
             t1.date as date1,
             ifnull(t3.user_id, t1.user_id) as user_id,
             t1.value1,
             t1.value2,
             t2.value3
      from t2
             join t3 on t3.t3_id=t2.id
             right join t1 on yearweek(t1.date) = yearweek(t2.date) and t1.user_id = t3.user_id) as q1

group by week_year, user_id;

DB Fiddle

Является ли текущее решение приемлемым с точки зрения производительности или есть лучшие варианты?В случае, если в будущем будет добавлена ​​третья (или четвертая) таблица, как бы я справился с запросом?Стоит ли создавать отдельную таблицу, которая обновляется с помощью триггеров?

Заранее спасибо.

1 Ответ

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

Другой способ сделать это - объединить все данные и затем сгруппировать их.Вам нужно пройти тестирование, чтобы увидеть, что лучше:

SELECT

  yearweek(date), 
  SUM(value1) as sum1,
  AVG(value2) as avg1,
  SUM(value3) as sum2
FROM
(
  SELECT user_id, date, value1, value2, CAST(null as INT) as value3 FROM t1
  UNION ALL 
  SELECT user_id, date, null, null, value3 FROM t2 INNER JOIN t3 ON t2.id = t3.t3_id
)
GROUP BY
  user_id,
  yearweek(date)

Надеюсь, mysql не будет иметь проблем с приведением null к int ..

...