ROW_NUMBER() în MySQL

Numerotează rândurile 1, 2, 3... în fiecare grup, fără să le comprime ca GROUP BY.

Sintaxă
ROW_NUMBER() OVER ([PARTITION BY ...] ORDER BY ...)

Ce face ROW_NUMBER()

Funcțiile fereastră calculează valori pe un grup de rânduri, dar păstrează fiecare rând în rezultat. Grupul se definește cu OVER (PARTITION BY ... ORDER BY ...).

ROW_NUMBER() dă fiecărui rând un număr unic, în ordinea din ORDER BY, reluat de la 1 pentru fiecare partiție. Este soluția clasică pentru „primele N din fiecare grup”.

Parametri

Parametru Descriere
PARTITION BY Opțional. Coloanele după care se împart rândurile în grupuri.
ORDER BY Ordinea numerotării.

Ce returnează

Un număr întreg de la 1 în sus.

Exemple

Exemplele de pe această pagină pornesc de la datele de mai jos. Rulează mai întâi acest cod, apoi exemplul.

CREATE TABLE vanzari (
  agent VARCHAR(20),
  oras VARCHAR(20),
  luna INT,
  suma INT
);

INSERT INTO vanzari VALUES
  ('Ana', 'Iași', 1, 1200), ('Ana', 'Iași', 2, 1500), ('Ana', 'Iași', 3, 900),
  ('Dan', 'Cluj', 1, 900), ('Dan', 'Cluj', 2, 900), ('Dan', 'Cluj', 3, 1700),
  ('Ioana', 'Iași', 1, 2000), ('Ioana', 'Iași', 2, 1100);

Exemplul 1: Numerotarea lunilor fiecărui agent

SELECT agent, luna, suma,
       ROW_NUMBER() OVER (PARTITION BY agent ORDER BY suma DESC) AS loc
FROM vanzari
ORDER BY agent, loc;

Rezultat

+-------+------+------+-----+
| agent | luna | suma | loc |
+-------+------+------+-----+
| Ana   |    2 | 1500 |   1 |
| Ana   |    1 | 1200 |   2 |
| Ana   |    3 |  900 |   3 |
| Dan   |    3 | 1700 |   1 |
| Dan   |    1 |  900 |   2 |
| Dan   |    2 |  900 |   3 |
| Ioana |    1 | 2000 |   1 |
| Ioana |    2 | 1100 |   2 |
+-------+------+------+-----+

Exemplul 2: Cea mai bună lună a fiecărui agent

SELECT agent, luna, suma
FROM (
  SELECT agent, luna, suma,
         ROW_NUMBER() OVER (PARTITION BY agent ORDER BY suma DESC) AS loc
  FROM vanzari
) AS t
WHERE loc = 1
ORDER BY agent;

Rezultat

+-------+------+------+
| agent | luna | suma |
+-------+------+------+
| Ana   |    2 | 1500 |
| Dan   |    3 | 1700 |
| Ioana |    1 | 2000 |
+-------+------+------+

Greșeli frecvente

  • Pui condiția WHERE ROW_NUMBER() ... direct. Funcțiile fereastră se calculează după WHERE, deci trebuie o subinterogare (sau un CTE) ca în exemplul 2.

Comenzi înrudite

  • RANK(): Clasament cu locuri egale la valori egale și „găuri” după ele (1, 2, 2, 4).
  • DENSE_RANK(): Clasament cu locuri egale la valori egale, fără „găuri” (1, 2, 2, 3).
  • NTILE(): Împarte rândurile în N grupe cât mai egale și spune în care grupă este fiecare rând.