25/27.02. Dodeljivanje rednih brojeva –> ROW_NUMBER()
U radu sa bazama podataka često želimo da:
* numerišemo rezultate upita (1, 2, 3, 4…)
* pronađemo prvih N rezultata
* pronađemo najbolje rezultate po grupama
* uklonimo duplikate
* napravimo rang listu .....
Za to koristimo funkciju ROW_NUMBER().
Osnovna sintaksa
ROW_NUMBER() OVER (ORDER BY kolona)
Ili sa grupisanjem:
ROW_NUMBER() OVER (PARTITION BY kolona ORDER BY kolona)
📌 Objašnjenje:
| Deo | Značenje |
| ROW_NUMBER() | Funkcija koja dodeljuje redni broj |
| OVER | Označava da je ovo prozor funkcija |
| ORDER BY | Obavezno – definiše redosled numeracije |
| PARTITION BY | (nije obavezno) – deli podatke u grupe |
Primer 1 – Jednostavno numerisanje učenika
Kreiranje tabele
CREATE TABLE Ucenici (
UcenikID INT PRIMARY KEY,
Ime NVARCHAR(50),
Prezime NVARCHAR(50),
Prosek DECIMAL(3,2)
);
Unos podataka
INSERT INTO Ucenici VALUES
(1, 'Marko', 'Markovic', 4.50),
(2, 'Ana', 'Petrovic', 5.00),
(3, 'Jovan', 'Jovanovic', 3.80),
(4, 'Milica', 'Nikolic', 4.90),
(5, 'Ivan', 'Ilic', 4.20);
Upit: Numerisanje po proseku (od najboljeg)
SELECT
ROW_NUMBER() OVER (ORDER BY Prosek DESC) AS RedniBroj,
Ime,
Prosek
FROM Ucenici;
Objašnjenje
* ORDER BY Prosek DESC → Najveći prosek dobija broj 1
* Svaki sledeći učenik dobija sledeći broj
Rezultat:
| RedniBroj | Ime | Prosek |
| --------- | ------ | ------ |
| 1 | Ana | 5.00 |
| 2 | Milica | 4.90 |
| 3 | Marko | 4.50 |
| 4 | Ivan | 4.20 |
| 5 | Jovan | 3.80 |
Primer 2 – Numerisanje unutar grupa (PARTITION BY) -> Sada želimo da numerišemo učenike po odeljenjima.
Kreiranje nove tabele
CREATE TABLE UceniciOdeljenje (
UcenikID INT PRIMARY KEY,
Ime NVARCHAR(50),
Odeljenje NVARCHAR(10),
Prosek DECIMAL(3,2)
);
Unos podataka
INSERT INTO UceniciOdeljenje VALUES
(1, 'Marko', 'III-1', 4.50),
(2, 'Ana', 'III-1', 5.00),
(3, 'Jovan', 'III-2', 3.80),
(4, 'Milica', 'III-2', 4.90),
(5, 'Ivan', 'III-1', 4.20),
(6, 'Sara', 'III-2', 5.00);
Upit
SELECT
ROW_NUMBER() OVER (PARTITION BY Odeljenje ORDER BY Prosek DESC) AS RedniBroj,
Ime,
Odeljenje,
Prosek
FROM UceniciOdeljenje;
Objašnjenje
* PARTITION BY Odeljenje → Svako odeljenje počinje numeraciju od 1
* ORDER BY Prosek DESC → Najbolji učenik u odeljenju dobija broj 1
Rezultat:
| RedniBroj | Ime | Odeljenje | Prosek |
| --------- | ------ | ------ | ------ |
| 1 | Ana | III-1 | 5.00 |
| 2 | Marko | III-1 | 4.50 |
| 3 | Ivan | III-1 | 4.20 |
| 1 | Sara | III-2 | 5.00 |
| 2 | Milica | III-2 | 4.90 |
| 3 | Jovan | III-2 | 3.80 |
ROW_NUMBER() u podupitu
Često se koristi u podupitu da bismo izdvojili npr. samo prva 3 učenika.
Primer – Najbolja 3 učenika
SELECT *
FROM
(
SELECT
ROW_NUMBER() OVER (ORDER BY Prosek DESC) AS RedniBroj,
Ime,
Prezime,
Prosek
FROM Ucenici
) AS Tabela
WHERE RedniBroj <= 3;
Objašnjenje
1. Prvo se numerišu svi učenici
2. Spoljašnji upit filtrira samo prve 3
Primer 3 – Uklanjanje duplikata
Kreiranje tabele
CREATE TABLE Proizvodi (
ProizvodID INT,
Naziv NVARCHAR(50),
Cena DECIMAL(10,2)
);
Unos podataka
INSERT INTO Proizvodi VALUES
(1, 'Laptop', 60000),
(1, 'Laptop', 60000),
(2, 'Mis', 1500),
(2, 'Mis', 1500),
(3, 'Tastatura', 3000);
Uklanjanje duplikata
WITH CTE AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY ProizvodID ORDER BY ProizvodID) AS RN
FROM Proizvodi
)
DELETE FROM CTE WHERE RN > 1;
Objašnjenje
* Svaki duplikat dobija broj
* Zadržava se prvi (RN = 1)
* Brišu se ostali
Vežbe sa rešenjima
Vežba 1 - Prikazati sve učenike numerisane po prezimenu (A-Ž).
Rešenje
SELECT
ROW_NUMBER() OVER (ORDER BY Prezime ASC) AS RedniBroj,
Ime,
Prezime
FROM Ucenici;
Vežba 2 - Pronaći najboljeg učenika u svakom odeljenju.
Rešenje
SELECT *
FROM
(
SELECT
ROW_NUMBER() OVER (PARTITION BY Odeljenje ORDER BY Prosek DESC) AS RN,
Ime,
Odeljenje,
Prosek
FROM UceniciOdeljenje
) AS T
WHERE RN = 1;
Zadaci za vežbu kod kuće
🔹 Zadatak 1 - Prikazati 2 najskuplja proizvoda iz tabele Proizvodi.
🔹 Zadatak 2 - Numerisati učenike po odeljenjima, ali po rastućem proseku.
🔹 Zadatak 3 - Napraviti tabelu Radnici (RadnikID, Ime, Plata, Sektor). Prikazati 3 radnika sa najvećom platom u svakom sektoru.
Treba zapamtiti
✅ ROW_NUMBER() uvek mora imati OVER()
✅ ORDER BY je obavezan
✅ PARTITION BY deli podatke u grupe
✅ Često se koristi u podupitima
✅ Koristi se za top N rezultate i uklanjanje duplikata