AKTUALIZUJ
MySQL 8.0 wprowadza "funkcje okien", funkcjonalność równoważną "funkcjom okien" SQL Server (z partycjonowaniem i porządkowaniem zapewnianymi przez Transact-SQL OVER
składni) i „funkcje analityczne” Oracle
Podręcznik MySQL 12.21 Funkcje okien https://dev.mysql .com/doc/refman/8.0/en/window-functions.html
Odpowiedź podana tutaj jest podejściem dla wersji MySQL wcześniejszych niż 8.0.
PIERWOTNA ODPOWIEDŹ
MySQL nie zapewnia funkcji analitycznej typu, której można by użyć do uzyskania działającej „sumy zbiorczej”, takiej jak funkcje analityczne dostępne w innych DBMS (takich jak Oracle lub SQL Server).
Ale możliwe jest emulowanie niektórych funkcji analitycznych za pomocą MySQL.
Istnieją (co najmniej) dwa praktyczne podejścia:
Jednym z nich jest użycie skorelowanego podzapytania, aby uzyskać sumę pośrednią. Takie podejście może być kosztowne w przypadku dużych zestawów i skomplikowane, jeśli predykaty w zapytaniu zewnętrznym są skomplikowane. To naprawdę zależy od tego, jak skomplikowane jest „wielokrotne złączenia na wielu tabelach”. (Niestety, MySQL również nie obsługuje CTE).
Innym podejściem jest wykorzystanie zmiennych użytkownika MySQL, aby wykonać przetwarzanie przerwań kontrolnych. „Sztuczka” polega na posortowaniu wyników zapytania (za pomocą ORDER BY), a następnie umieszczeniu zapytania w innym zapytaniu.
Podam przykład tego drugiego podejścia.
Ze względu na kolejność wykonywania operacji przez MySQL, cumulative_total
kolumna musi być obliczona przed wartością z id
i day
z bieżącego wiersza są zapisywane w zmiennych użytkownika. Po prostu najłatwiej jest umieścić tę kolumnę na początku.
Widok wbudowany aliasowany jako i (w poniższym zapytaniu) służy tylko do inicjowania zmiennych użytkownika, na wypadek, gdyby zostały już ustawione w sesji. Jeśli mają już przypisane wartości, chcemy zignorować ich bieżące wartości, a najłatwiejszym sposobem na to jest ich inicjalizacja.
Twoje oryginalne zapytanie jest umieszczane w nawiasach i otrzymuje alias c
w poniższym przykładzie. Jedyną zmianą w pierwotnym zapytaniu jest dodanie klauzuli ORDER BY, dzięki czemu możemy być pewni, że wiersze z zapytania zostaną przetworzone po kolei.
Zewnętrzny wybór sprawdza, czy id
i day
wartość z bieżącego wiersza „pasuje” do poprzedniego wiersza. Jeśli tak, dodajemy amount
od bieżącego wiersza do skumulowanej sumy częściowej. Jeśli się nie zgadzają, resetujemy skumulowaną sumę częściową do zera i dodajemy kwotę z bieżącego wiersza (lub, prościej, po prostu przypisujemy kwotę z bieżącego wiersza).
Po wykonaniu obliczenia skumulowanej sumy zapisujemy id
i day
wartości z bieżącego wiersza do zmiennych użytkownika, dzięki czemu są dostępne, gdy przetwarzamy następny wiersz.
Na przykład:
SELECT IF(@prev_id = c.id AND @prev_day = c.day
,@cumtotal := @cumtotal + c.amount
,@cumtotal := c.amount) AS cumulative_total
, @prev_id := c.id AS `id`
, @prev_day := c.day AS `day`
, c.hr
, c.amount AS `amount'
FROM ( SELECT @prev_id := NULL
, @prev_day := NULL
, @subtotal := 0
) i
JOIN (
select id, day, hr, amount from
( //multiple joins on multiple tables)a
left join
(//unions on multiple tables)b
on a.id=b.id
ORDER BY 1,2,3
) c
Jeśli konieczne jest zwrócenie kolumn w innej kolejności, ze skumulowaną sumą jako ostatnią kolumną, jedną z opcji jest owinięcie całej instrukcji zestawem nawiasów i użycie tego zapytania jako widoku wbudowanego:
SELECT d.id
, d.day
, d.hr
, d.amount
, d.cumulative_total
FROM (
// query from above
) d