Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jak zrobić sumę kroczącą, każdy wiersz musi zawierać sumę poprzednich wierszy

Możesz użyć zmiennych użytkownika MySQL do emulacji funkcji analitycznych. (Istnieją również inne podejścia, takie jak użycie częściowego sprzężenia lub użycie skorelowanego podzapytania. Mogę również dostarczyć rozwiązania dla nich, jeśli uważasz, że mogą być bardziej odpowiednie.)

Aby emulować funkcję analityczną „bieżąca suma”, wypróbuj coś takiego:

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

„Sztuczka” polega na użyciu funkcji JEŻELI do sprawdzenia, czy order_number nie ma wartości. Gdy ma wartość null, dodajemy wartość czasu trwania do zmiennej, w przeciwnym razie ustawiamy zmienną na zero.

Używamy widoku wbudowanego (alias d , aby upewnić się, że zmienna @tot_dur jest inicjowana na zero.

UWAGA:Zachowaj ostrożność podczas używania takich zmiennych użytkownika MySQL. W instrukcji SELECT, jak powyżej, przypisanie zmiennych na liście SELECT następuje po ORDER BY, więc możemy uzyskać zachowanie deterministyczne.

To zapytanie nie obsługuje „przerw” w identyfikatorze użytkownika. Aby to uzyskać, będziemy potrzebować wartości user_id z poprzedniego wiersza. Możemy to zachować w innej zmiennej użytkownika. Kolejność operacji jest deterministyczna i musimy zadbać o akumulację ZANIM nadpiszemy identyfikator użytkownika z poprzedniego wiersza.

Musimy albo zmienić kolejność kolumn, aby user_id pojawiał się po tot_dur (lub dołączyć drugą kopię kolumny 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

Wartości zwrócone w user_id i prev_user_id kolumny są identyczne. Ta „dodatkowa” kolumna może zostać usunięta lub można zmienić kolejność kolumn, zawijając zapytanie (jako widok wbudowany) w inne zapytanie, chociaż wiąże się to z kosztem wydajności:

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

Zapytanie to pokazuje, że MySQL może zwrócić określony zestaw wyników. Ale w celu uzyskania optymalnej wydajności chcielibyśmy uruchomić zapytanie tylko w widoku wbudowanym (o nazwie v ) i obsługuj zmianę kolejności kolumn (umieszczając kolumnę user_id jako pierwszą) po stronie klienta, gdy wiersze są pobierane.

Pozostałe dwa popularne podejścia to użycie częściowego sprzężenia i użycie skorelowanego podzapytania, chociaż te podejścia mogą wymagać więcej zasobów podczas przetwarzania dużych zbiorów.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Ten sam login na 2 stronach internetowych

  2. PHP Sprawdź ostatni wiersz MySQL

  3. Jak zsynchronizować bazę danych SQLServer i bazę danych MySQL

  4. Jak debugować procedury składowane MySQL?

  5. SQL Counter i returner, podwaja wynik