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.