Mysql
 sql >> база данни >  >> RDS >> Mysql

Как да направите подвижна сума, всеки ред трябва да включва сумата на предишните редове

Можете да използвате MySQL потребителски променливи, за да емулирате аналитични функции. (Има и някои други подходи, като използване на полуприсъединяване или използване на корелирана подзаявка. Мога да предоставя решения и за тях, ако смятате, че може да са по-подходящи.)

За емулиране на аналитична функция "изпълнена обща", опитайте нещо подобно:

SELECT t.user_id
     , t.starttime
     , t.order_number
     , IF(t.order_number IS NOT NULL,
         @tot_dur := 0,
         @tot_dur := @tot_dur + t.visit_duration_seconds) AS tot_dur
  FROM visit t
  JOIN (SELECT @tot_dur := 0) d
 ORDER BY t.user_id, t.start_time

"Тръкът" тук е да използвате функция IF, за да проверите дали order_number е нула. Когато е нула, добавяме стойността на продължителността към променливата, в противен случай задаваме променливата на нула.

Използваме вграден изглед (с псевдоним като d , за да се гарантира, че променливата @tot_dur е инициализирана на нула.

ЗАБЕЛЕЖКА:Внимавайте с използването на потребителски променливи на MySQL като тази. В оператора SELECT както по-горе, присвояването на променливите в списъка SELECT се случва след ORDER BY, така че можем да получим детерминирано поведение.

Тази заявка не обработва "прекъсвания" в user_id. За да получим това, ще ни трябва стойността на user_id от предишния ред. Можем да запазим това в друга потребителска променлива. Редът на операциите е детерминиран и трябва да се погрижим да извършим натрупването, ПРЕДИ да презапишем user_id от предишния ред.

Трябва или да пренаредим колоните, така че user_id да се появи след tot_dur (или да включим второ копие на колоната user_id)

SELECT t.user_id
     , t.starttime
     , t.order_number
     , IF(t.order_number IS NULL,
         @tot_dur := IF(@prev_user_id = t.user_id,@tot_dur,0) + t.visit_duration_seconds,
         @tot_dur := 0
       ) AS tot_dur
     , @prev_user_id := t.user_id AS prev_user_id
  FROM visit t
  JOIN (SELECT @tot_dur := 0, @prev_user_id := NULL) d
 ORDER BY t.user_id, t.start_time

Стойностите, върнати в user_id и prev_user_id колони е идентичен. Тази „допълнителна“ колона може да бъде премахната или колоните могат да бъдат пренаредени чрез обвиване на заявката (като вграден изглед) в друга заявка, въпреки че това идва с разходи за производителност:

SELECT v.user_id
     , v.starttime
     , v.order_number
     , v.tot_dur
  FROM (SELECT t.starttime
             , t.order_number
             , IF(t.order_number IS NULL,
                 @tot_dur := IF(@prev_user_id = t.user_id,@tot_dur,0) + t.visit_duration_seconds,
                 @tot_dur := 0
               ) AS tot_dur
             , @prev_user_id := t.user_id AS user_id
          FROM visit t
          JOIN (SELECT @tot_dur := 0, @prev_user_id := NULL) d
         ORDER BY t.user_id, t.start_time
       ) v

Тази заявка показва, че е възможно MySQL да върне посочения набор от резултати. Но за оптимална производителност бихме искали да изпълним само заявката във вградения изглед (с псевдоним като v ) и обработва пренареждането на колоните (поставяйки първо колоната user_id) от страна на клиента, когато редовете бъдат извлечени.

Другите два често срещани подхода използват полусъединяване и използване на корелирана подзаявка, въпреки че тези подходи могат да бъдат по-интензивни при обработка на големи набори.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL JDBC драйвер 5.1.33 – Проблем с часовата зона

  2. Настройка на MySQL за бързо създаване на колона/индекс по време на разработката

  3. Изтриване от MySQL таблица с ограничения на външния ключ

  4. Заместващият знак в най-лявата колона на съставния индекс означава ли, че останалите колони в индекса не се използват при търсене на индекс (MySQL)?

  5. Задействане за актуализиране на ред в друга таблица