sql >> Database teknologi >  >> RDS >> Mysql

Kumulativ sum over et sæt rækker i mysql

OPDATERING

MySQL 8.0 introducerer "vinduefunktioner", funktionalitet svarende til SQL Server "vinduefunktioner" (med partitionering og bestilling leveret af Transact-SQL OVER syntaks), og Oracle "analytiske funktioner".

MySQL Reference Manual 12.21 Vinduesfunktioner https://dev.mysql .com/doc/refman/8.0/da/window-functions.html

Svaret her er en tilgang til MySQL-versioner før 8.0.

ORIGINAL SVAR

MySQL leverer ikke den type analytiske funktion, du ville bruge til at få en kørende "kumulativ sum", ligesom de analytiske funktioner, der er tilgængelige i andre DBMS (som Oracle eller SQL Server.)

Men det er muligt at efterligne nogle analytiske funktioner ved hjælp af MySQL.

Der er (mindst) to brugbare tilgange:

Den ene er at bruge en korreleret underforespørgsel for at få subtotalen. Denne tilgang kan være dyr på store sæt og kompliceret, hvis prædikaterne på den ydre forespørgsel er komplicerede. Det afhænger virkelig af, hvor kompliceret "flere joinforbindelser på flere borde" er. (Desværre understøtter MySQL heller ikke CTE'er.)

Den anden tilgang er at gøre brug af MySQL-brugervariabler for at udføre en vis kontrolpausebehandling. "Tricket" her er at resultaterne fra din forespørgsel sorteres (ved hjælp af en ORDER BY) og derefter pakke din forespørgsel ind i en anden forespørgsel.

Jeg vil give et eksempel på den sidstnævnte tilgang.

På grund af den rækkefølge, som MySQL udfører operationer, er cumulative_total kolonne skal beregnes før værdien fra id og day fra den aktuelle række gemmes i brugervariabler. Det er bare nemmest at sætte denne kolonne først.

Inline-visningen kaldet i (i forespørgslen nedenfor) er kun til for at initialisere brugervariablerne, bare hvis disse allerede er indstillet i sessionen. Hvis disse allerede har værdier tildelt, vil vi ignorere deres nuværende værdier, og den nemmeste måde at gøre det på er at initialisere dem.

Din oprindelige forespørgsel bliver pakket ind i parentes og får et alias, c i eksemplet nedenfor. Den eneste ændring af din oprindelige forespørgsel er tilføjelsen af ​​en ORDER BY-klausul, så vi kan være sikre på, at vi behandler rækkerne fra forespørgslen i rækkefølge.

Den ydre markering kontrollerer, om id og day værdi fra den aktuelle række "matcher" den forrige række. Hvis de gør det, tilføjer vi amount fra den aktuelle række til den kumulative subtotal. Hvis de ikke stemmer overens, nulstiller vi den kumulative subtotal og tilføjer beløbet fra den aktuelle række (eller, mere enkelt, tildeler vi beløbet fra den aktuelle række).

Efter at vi har foretaget beregningen af ​​den kumulative total, gemmer vi id og day værdier fra den aktuelle række til brugervariable, så de er tilgængelige, når vi behandler den næste række.

For eksempel:

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

Hvis det er nødvendigt at returnere kolonnerne i en anden rækkefølge, med kumulativ total som den sidste kolonne, så er en mulighed at pakke hele sætningen ind i et sæt parentes og bruge den forespørgsel som en indlejret visning:

SELECT d.id
     , d.day
     , d.hr
     , d.amount
     , d.cumulative_total
FROM (
       // query from above
     ) d
 


  1. Sådan fungerer CHR() i MariaDB

  2. Sådan kontrolleres om mysql-databasen eksisterer

  3. Hvad er et gratis værktøj til at sammenligne to SQL Server-databaser?

  4. Konfiguration af en lytter i Oracle Database (12c, 18c og 19c udgaver)