Садржај
3.0 SQL: Промена садржаја базе
3.2 SQL: Ажурирање података у табелама
3.3 SQL: Брисање података из табела
7.0 Библиотека Flask - пројектни задатак

Угнежђени упити

Код сложенијих упита може бити потребно да се упит формира тако да се до резултата долази кроз неколико фаза. Свака фаза се формулише као нови SELECT упит који поред полазних табела може да користи и резултат упита из претходне фазе.

Прикажимо ово кроз неколико примера.

Приказати највећи број остварених оправданих изостанака неког ученика.

У првој фази формулишемо упит који за сваког ученика израчунава број оправданих изостанака. Ово је класичан упит у ком се врши груписање и израчунавање статистика (овај пут броја елемената сваке групе).

SELECT COUNT(*) AS broj
FROM izostanak
WHERE status = 'оправдан'
GROUP BY id_ucenik

Извршавањем упита добија се следећи резултат:

broj

41

37

26

7

25

до коначног резултата можемо да стигнемо тако што из табеле која се добија као резултат претходног упита израчунамо максималну вредност колоне broj. То се лако постиже коришћењем агрегатне функције MAX.

SELECT MAX(broj)
FROM
    (SELECT COUNT(*) AS broj
     FROM izostanak
     WHERE status = 'оправдан'
     GROUP BY id_ucenik);

Извршавањем упита добија се следећи резултат:

MAX(broj)

71


Приказати просечне оцене свих предмета који се предају у првом разреду.

Овај задатак може да се реши спајањем (и то је пожељно решење, поготово ако се жели приказ назива предмета). Могуће је и решење засновано на угнежђеним упитима, тако што се у првој фази из табеле предмета издвоје идентификатори предмета који се предају у првом разреду, а онда се тај скуп идентификатора у другој фази употреби за издвајање одговарајућих оцена из табеле оцена, пре груписања и рачунања статистика по групама.

SELECT id_predmet, round(AVG(ocena), 2) AS prosek
FROM ocena
WHERE id_predmet IN (SELECT id
                     FROM predmet
                     WHERE razred = 1)
GROUP BY id_predmet;

Извршавањем упита добија се следећи резултат:

id_predmet

prosek

1

3.41

2

3.61

3

3.61

6

3.58

12

3.63


Приказати називе предмета и просечне оцене на писменим задацима за све предмете код којих је просечна оцена на писменим задацима бар 3,50.

Када бисмо се задовољили само приказом идентификатора предмета, онда бисмо све могли да решимо упитом над табелом оцена, груписањем на основу идентификатора предмета, израчунавањем просека оцена за сваку групу и затим селекцијом оних предмета код којих је просечна оцена већа од 3,5. Пошто су нам потребни називи предмета, можемо извршити спајање овако добијеног резултата упита са табелом предмета у којој се налазе идентификатори и називи предмета.

SELECT naziv, prosek
FROM predmet
     JOIN (SELECT id_predmet, round(AVG(ocena), 2) AS prosek
           FROM ocena
           WHERE ocena.vrsta = 'писмени задатак'
           GROUP BY id_predmet
           HAVING prosek >= 3.50)
       ON predmet.id = id_predmet;

Извршавањем упита добија се следећи резултат:

naziv

prosek

Српски језик

3.98


За свако одељење приказати највећи број оправданих изостанака.

У првој фази можемо да изградимо табелу која за сваког ученика садржи идентификатор, разред и одељење и број оправданих изостанака. Пошто се разред и одељење налазе у табели ученика, а број изостанака се рачуна на основу података у табели изостанака, прво вршимо спајање те две табеле, вршимо селекцију само оправданих изостанака, а након тога групишемо податке на основу идентификатора ученика и применом COUNT(*) одређујемо број оправданих изостанака.

SELECT ucenik.id, razred, odeljenje, COUNT(*) as broj_opravdanih
FROM izostanak
     JOIN ucenik on izostanak.id_ucenik = ucenik.id
WHERE status = 'оправдан'
GROUP BY ucenik.id

Извршавањем упита добија се следећи резултат:

id

razred

odeljenje

broj_opravdanih

1

1

1

41

2

1

1

37

4

2

1

26

5

2

1

7

6

1

2

25

Када је у првој фази одређена оваква помоћна табела, тада у другој фази лако можемо да одредимо максималан број оправданих изостанака за свако одељење (груписањем на основу разреда и одељења и применом агрегатне функције MAX).

SELECT razred, odeljenje, MAX(broj_opravdanih)
FROM (SELECT ucenik.id, razred, odeljenje, COUNT(*) as broj_opravdanih
      FROM izostanak
           JOIN ucenik on izostanak.id_ucenik = ucenik.id
      WHERE status = 'оправдан'
      GROUP BY ucenik.id)
GROUP BY razred, odeljenje;

Извршавањем упита добија се следећи резултат:

razred

odeljenje

MAX(broj_opravdanih)

1

1

55

1

2

67

1

3

60

2

1

53

2

2

60

Приметимо да табела добијена као резултат угнежђеног подупита нема назив. Ако је потребно да јој дамо назив, то се може урадити навођењем алијаса, коришћењем кључне речи AS (у облику FROM (SELECT ...) AS naziv). Алијасе смо раније користили за именовање колона, док се овај пут именује табела.

Вежба

Покушај да самостално напишеш наредни упит, коришћењем угнежћених упита.

За сваки разред и одељење прикажи највећу просечну оцену коју је постигао неки ученик у том одељењу (рачунати укупан просек свих уписаних оцена и заокружити га на две децимале).



(Created using Swinx, RunestoneComponents and PetljaDoc)
© 2022 Petlja
A- A+