Создать столбец, представляющий индекс строки в группе - PullRequest
1 голос
/ 24 марта 2019

У меня есть случай, когда у меня есть таблица, которая описывает измерения на определенную дату.Однако существуют разные типы измерений (которые могут иметь одинаковую дату).Таблица выглядит примерно так:

Table: measurements

type_id     date        value
--------------------------------
1           2018-12-31  40
1           2019-01-01  42
1           2019-01-02  43
1           2019-01-04  44
2           2019-01-01  80
2           2019-01-02  79
2           2019-01-05  78

(обратите внимание, что 1 / 2019-01-03 и 2 / 2019-01-03 и 2 / 2019-01-04 опущены!)

Различные типы не сопоставимы друг с другом и поэтому должны быть строго отделены друг от друга.Проблема в том, что мне нужно объединить эту таблицу с другой таблицей, порядок которой не основан на датах, но использует подход смещения / индекса (целое число), основанный на базовой дате (откуда начинается подсчет)!Обратите внимание, что этот индекс подсчитывает строк и не является смещением в терминах «дней с ...».

Для примера здесь давайте предположим, что это выглядит так (упрощено из реальной жизни):

Table: type_master

type_id         base_date
--------------------------
1               2019-01-01
2               2019-01-01
3               2018-12-22
...

Вот почему я хотел бы иметь «индекс числа строк в каждой группе».Таким образом, результирующий набор оператора SQL (который будет выполняться на MySQL / MariaDB) должен выглядеть примерно так:

type_id      date      value   index_in_group
-------------------------------------------
1           2018-12-31  40     null (and not -1!)
1           2019-01-01  42     1
1           2019-01-02  43     2
1           2019-01-04  44     3  (and not 4!)
2           2019-01-01  80     1
2           2019-01-02  79     2
2           2019-01-05  78     3  (and not 5!)

(индексация должна выполняться в порядке возрастания по дате - вы можете предположить, что этидаты, которые пропускаются, также пропускаются намеренно).

Я уже начал играть с идеей, упомянутой в https://stackoverflow.com/a/5351692/6350762

select @n := @n + 1 index, m.*
from (select @n:=0) initvars, measurements m

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

Вы также можете учитывать следующее:

  • Если возможно, все это в конечном итоге должно закончитьсяв представлении.
  • Написание процедуры MySQL было бы возможно, но привело бы к нежелательным побочным эффектам - если бы это было так, то я мог бы также реализовать необходимую логику на сервере приложений, который выполняется поверхбаза данных.Однако наличие логики в базе данных было бы предпочтительным из-за причин доступа к данным.
  • Хорошая производительность была бы хорошей, но это не имеет первостепенного значения: количество записей в measurements имеет порядок40k;количество записей на type_master составляет несколько десятков.
  • Сервер работает на MariaDB 10.1.26.( Обновлено позже на основе комментария )

Есть идеи, как мне этого добиться с помощью приемлемого оператора SQL?

1 Ответ

1 голос
/ 24 марта 2019

В MySQL 8+ и в последних версиях MariaDB вы можете использовать оконные функции:

select m.*,
       (case when m.date >= tm.base_date 
             then row_number() over (partition by type_id,
                                                  m.date >= tm.base_date
                                     order by m.date
                                    )
        end) as index_in_group
from measurements m left join
     type_master tm
     on m.type_id = tm.type_id;

В старых версиях вы можете использовать переменные. Это немного сложно; Я думаю, что логика:

select m.*,
       (@rn := if(m.date < tm.base_date, NULL,
                  if(@t = m.type_id, @rn + 1,
                     if(@t := m.type_id, 1, 1)
                    )
                 )
       ) as index_in_group
from (select m.*, tm.base_date
      from measurements m left join
           type_master tm
           on m.type_id = tm.type_id
      order by m.type_id, m.date
     ) m cross join
     (select @t := -1, @rn := 0) params
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...