Changes between Version 5 and Version 6 of AdvancedReports


Ignore:
Timestamp:
09/30/26 17:23:35 (104 minutes ago)
Author:
223306
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AdvancedReports

    v5 v6  
    11= Advanced Reports =
    22
    3 Во оваа фаза се изработени два комплексни аналитички извештаи над податоците од базата на !BiblioPremium.
    4 
    5 Извештаите се наменети за долгорочна анализа на работењето на системот и користат податоци од повеќе релации, повеќестепено агрегирање, временска анализа, CTE (Common Table Expressions), прозорски функции, рангирање и пресметани аналитички показатели.
    6 
    7 Во двата извештаи се земаат предвид само реализираните нарачки со статус ''ZAVRSENA''.
     3Во оваа фаза се изработени два комплексни аналитички извештаи за системот !BiblioPremium.
     4
     5Извештаите се наменети за анализа на продажбата во подолг временски период. Се користат податоци од повеќе поврзани релации, агрегатни функции, временско групирање и прозорски функции.
     6
     7Во анализите се земаат предвид само реализираните нарачки со статус ''ZAVRSENA''.
    88
    99Во релационата алгебра се користи проширена нотација:
    1010
    1111* σ – селекција
    12 * π – генерализирана проекција со пресметани атрибути
     12* π – проекција
    1313* ⋈ – спојување
    14 * ⟕ – лево надворешно спојување
    15 * ρ – преименување
    1614* γ – групирање и агрегатни функции
    1715* τ – подредување
    1816* ← – доделување на привремена релација
    1917
    20 За аналитичките операции како RANK, DENSE_RANK, LAG, ROW_NUMBER и подвижни агрегати се користи проширена аналитичка нотација.
    21 
    22 
    23 == Квартална анализа и рангирање на продажните перформанси на книгите по категории ==
     18
     19== Квартална анализа на продажбата на книги по категории ==
    2420
    2521=== Data requirements description ===
    2622
    27 Целта на извештајот е да се анализира како се менува продажбата на книгите и категориите низ кварталите и да се идентификуваат книгите кои имаат најголемо влијание врз приходот.
    28 
    29 За секој квартал, категорија и книга потребно е да се прикажат:
    30 
     23Целта на извештајот е да се анализира продажбата на книгите по квартали и категории.
     24
     25За секој квартал и книга се пресметуваат:
     26
     27* категоријата на книгата;
    3128* бројот на различни реализирани нарачки;
    32 * вкупниот број на продадени примероци;
    33 * вкупниот остварен приход;
     29* бројот на продадени примероци;
     30* вкупниот приход;
    3431* просечната продажна цена;
    35 * вкупниот приход на категоријата во кварталот;
    36 * просечниот приход по продавана книга во категоријата;
    37 * рангот на книгата во рамки на категоријата за конкретниот квартал;
    38 * процентуалното учество на книгата во приходот на категоријата;
     32* рангот на книгата во рамки на категоријата;
    3933* приходот на истата книга во претходниот достапен квартал;
    40 * процентуалната промена на приходот во однос на претходниот достапен квартал;
    41 * кумулативниот приход на книгата низ кварталите;
    42 * класификација на трендот на продажба.
    43 
    44 Извештајот овозможува квартално, полугодишно, годишно и повеќегодишно следење на продажбата.
    45 
    46 Со него може да се утврди кои книги носат најголем приход во својата категорија, како нивната продажба се менува низ времето и дали одредена книга покажува растечки или опаѓачки тренд.
     34* процентуалната промена на приходот;
     35* тренд на продажбата.
     36
     37На овој начин може да се следи кои книги се најуспешни во одредена категорија и дали нивната продажба расте или опаѓа низ времето.
     38
     39Извештајот може да се користи на квартално, полугодишно, годишно и повеќегодишно ниво.
    4740
    4841
    … …  
    5043
    5144{{{
    52 WITH quarterly_book_sales AS (
     45WITH quarterly_sales AS (
    5346    SELECT
    5447        DATE_TRUNC('quarter', n.datum) AS kvartal,
    5548        k.kniga_id,
    5649        k.naslov,
    57         k.isbn,
    5850        kat.kategorija_id,
    5951        kat.naziv AS kategorija,
    … …  
    6759        ) AS vkupen_prihod,
    6860
    69         AVG(
    70             s.edinechna_cena
    71         ) AS prosecna_prodazna_cena
     61        AVG(s.edinechna_cena) AS prosecna_cena
    7262
    7363    FROM project.knigi k
    … …  
    9181        k.kniga_id,
    9282        k.naslov,
    93         k.isbn,
    9483        kat.kategorija_id,
    9584        kat.naziv
    9685),
    9786
    98 category_statistics AS (
    99     SELECT
    100         kvartal,
    101         kategorija_id,
    102         kategorija,
    103 
    104         COUNT(DISTINCT kniga_id)
    105             AS broj_prodavani_knigi,
    106 
    107         SUM(vkupno_prodadeni)
    108             AS vkupno_prodadeni_kategorija,
    109 
    110         SUM(vkupen_prihod)
    111             AS vkupen_prihod_kategorija,
    112 
    113         AVG(vkupen_prihod)
    114             AS prosechen_prihod_po_kniga
    115 
    116     FROM quarterly_book_sales
    117 
    118     GROUP BY
    119         kvartal,
    120         kategorija_id,
    121         kategorija
    122 ),
    123 
    124 quarterly_analysis AS (
    125     SELECT
    126         qbs.kvartal,
    127         qbs.kniga_id,
    128         qbs.naslov,
    129         qbs.isbn,
    130         qbs.kategorija_id,
    131         qbs.kategorija,
    132         qbs.broj_naracki,
    133         qbs.vkupno_prodadeni,
    134         qbs.vkupen_prihod,
    135         qbs.prosecna_prodazna_cena,
    136 
    137         cs.broj_prodavani_knigi,
    138         cs.vkupno_prodadeni_kategorija,
    139         cs.vkupen_prihod_kategorija,
    140         cs.prosechen_prihod_po_kniga,
    141 
    142         RANK() OVER (
    143             PARTITION BY
    144                 qbs.kvartal,
    145                 qbs.kategorija_id
    146             ORDER BY
    147                 qbs.vkupen_prihod DESC
    148         ) AS rang_vo_kategorija,
    149 
    150         LAG(qbs.vkupen_prihod) OVER (
    151             PARTITION BY
    152                 qbs.kniga_id,
    153                 qbs.kategorija_id
    154             ORDER BY
    155                 qbs.kvartal
    156         ) AS prihod_prethoden_kvartal,
    157 
    158         SUM(qbs.vkupen_prihod) OVER (
    159             PARTITION BY
    160                 qbs.kniga_id,
    161                 qbs.kategorija_id
    162             ORDER BY
    163                 qbs.kvartal
    164             ROWS BETWEEN
    165                 UNBOUNDED PRECEDING
    166                 AND CURRENT ROW
    167         ) AS kumulativen_prihod
    168 
    169     FROM quarterly_book_sales qbs
    170 
    171     JOIN category_statistics cs
    172         ON qbs.kvartal = cs.kvartal
    173         AND qbs.kategorija_id = cs.kategorija_id
    174 ),
    175 
    176 final_analysis AS (
     87sales_analysis AS (
    17788    SELECT
    17889        *,
    17990
    180         ROUND(
    181             (
    182                 vkupen_prihod
    183                 /
    184                 NULLIF(
    185                     vkupen_prihod_kategorija,
    186                     0
    187                 )
    188             ) * 100,
    189             2
    190         ) AS procent_od_prihod_na_kategorija,
    191 
    192         ROUND(
    193             (
    194                 (
    195                     vkupen_prihod -
    196                     prihod_prethoden_kvartal
    197                 )
    198                 /
    199                 NULLIF(
    200                     prihod_prethoden_kvartal,
    201                     0
    202                 )
    203             ) * 100,
    204             2
    205         ) AS promena_prihod_procent,
    206 
    207         CASE
    208             WHEN prihod_prethoden_kvartal IS NULL
    209                 THEN 'NEMA PRETHODEN PERIOD'
    210 
    211             WHEN vkupen_prihod >
    212                  prihod_prethoden_kvartal * 1.10
    213                 THEN 'RAST'
    214 
    215             WHEN vkupen_prihod <
    216                  prihod_prethoden_kvartal * 0.90
    217                 THEN 'PAD'
    218 
    219             ELSE 'STABILNO'
    220         END AS trend
    221 
    222     FROM quarterly_analysis
     91        RANK() OVER (
     92            PARTITION BY kvartal, kategorija_id
     93            ORDER BY vkupen_prihod DESC
     94        ) AS rang_vo_kategorija,
     95
     96        LAG(vkupen_prihod) OVER (
     97            PARTITION BY kniga_id, kategorija_id
     98            ORDER BY kvartal
     99        ) AS prihod_prethoden_kvartal
     100
     101    FROM quarterly_sales
    223102)
    224103
    225104SELECT
    226     TO_CHAR(
    227         kvartal,
    228         'YYYY-"Q"Q'
    229     ) AS kvartal,
     105    TO_CHAR(kvartal, 'YYYY-"Q"Q') AS kvartal,
    230106
    231107    kategorija,
    232108    kniga_id,
    233109    naslov,
    234     isbn,
    235110
    236111    broj_naracki,
    237112    vkupno_prodadeni,
    238113
     114    ROUND(vkupen_prihod, 2) AS vkupen_prihod,
     115
     116    ROUND(prosecna_cena, 2) AS prosecna_cena,
     117
     118    rang_vo_kategorija,
     119
    239120    ROUND(
    240         vkupen_prihod,
    241         2
    242     ) AS vkupen_prihod,
    243 
    244     ROUND(
    245         prosecna_prodazna_cena,
    246         2
    247     ) AS prosecna_prodazna_cena,
    248 
    249     broj_prodavani_knigi,
    250 
    251     vkupno_prodadeni_kategorija,
    252 
    253     ROUND(
    254         vkupen_prihod_kategorija,
    255         2
    256     ) AS vkupen_prihod_kategorija,
    257 
    258     ROUND(
    259         prosechen_prihod_po_kniga,
    260         2
    261     ) AS prosechen_prihod_po_kniga,
    262 
    263     rang_vo_kategorija,
    264 
    265     procent_od_prihod_na_kategorija,
    266 
    267     ROUND(
    268         COALESCE(
    269             prihod_prethoden_kvartal,
    270             0
    271         ),
     121        COALESCE(prihod_prethoden_kvartal, 0),
    272122        2
    273123    ) AS prihod_prethoden_kvartal,
    274124
    275     promena_prihod_procent,
    276 
    277125    ROUND(
    278         kumulativen_prihod,
     126        (
     127            (vkupen_prihod - prihod_prethoden_kvartal)
     128            /
     129            NULLIF(prihod_prethoden_kvartal, 0)
     130        ) * 100,
    279131        2
    280     ) AS kumulativen_prihod,
    281 
    282     trend
    283 
    284 FROM final_analysis
     132    ) AS promena_prihod_procent,
     133
     134    CASE
     135        WHEN prihod_prethoden_kvartal IS NULL
     136            THEN 'NEMA PRETHODEN PERIOD'
     137
     138        WHEN vkupen_prihod >
     139             prihod_prethoden_kvartal * 1.10
     140            THEN 'RAST'
     141
     142        WHEN vkupen_prihod <
     143             prihod_prethoden_kvartal * 0.90
     144            THEN 'PAD'
     145
     146        ELSE 'STABILNO'
     147    END AS trend
     148
     149FROM sales_analysis
    285150
    286151ORDER BY
    287152    kvartal,
    288153    kategorija,
    289     rang_vo_kategorija,
    290     naslov;
     154    rang_vo_kategorija;
    291155}}}
    292156
    … …  
    294158=== Solution Relational Algebra ===
    295159
    296 Најпрво се издвојуваат само реализираните нарачки:
     160Прво се издвојуваат реализираните нарачки:
    297161
    298162{{{
    … …  
    311175}}}
    312176
    313 Потоа се додаваат ставките и реализираните нарачки:
     177Потоа се додаваат ставките од нарачките и реализираните нарачки:
    314178
    315179{{{
    … …  
    325189}}}
    326190
    327 Датумот се трансформира во квартал и се врши првото ниво на агрегација:
    328 
    329 {{{
    330 QBS ←
     191Продажбата се групира по квартал, книга и категорија:
     192
     193{{{
     194QS ←
    331195quarter(datum),
    332196kniga_id,
    333197naslov,
    334 isbn,
    335198kategorija_id,
    336199kategorija
    … …  
    338201γ
    339202
    340 COUNT-DISTINCT(naracka_id)
    341     → broj_naracki,
    342 
    343 SUM(kolicina)
    344     → vkupno_prodadeni,
    345 
    346 SUM(kolicina × edinechna_cena)
    347     → vkupen_prihod,
    348 
    349 AVG(edinechna_cena)
    350     → prosecna_prodazna_cena
     203COUNT-DISTINCT(naracka_id) → broj_naracki,
     204SUM(kolicina) → vkupno_prodadeni,
     205SUM(kolicina × edinechna_cena) → vkupen_prihod,
     206AVG(edinechna_cena) → prosecna_cena
    351207
    352208(R2)
    353209}}}
    354210
    355 Второто ниво на агрегација се врши на ниво квартал–категорија:
    356 
    357 {{{
    358 CS ←
    359 kvartal,
    360 kategorija_id,
    361 kategorija
    362 
    363 γ
    364 
    365 COUNT-DISTINCT(kniga_id)
    366     → broj_prodavani_knigi,
    367 
    368 SUM(vkupno_prodadeni)
    369     → vkupno_prodadeni_kategorija,
    370 
    371 SUM(vkupen_prihod)
    372     → vkupen_prihod_kategorija,
    373 
    374 AVG(vkupen_prihod)
    375     → prosechen_prihod_po_kniga
    376 
    377 (QBS)
    378 }}}
    379 
    380 Двете нивоа на анализа се поврзуваат:
    381 
    382 {{{
    383 QA ←
    384 QBS
    385 ⋈ QBS.kvartal = CS.kvartal
    386   ∧ QBS.kategorija_id = CS.kategorija_id
    387 CS
    388 }}}
    389 
    390 Рангирањето во рамки на квартал и категорија се изразува со проширена аналитичка операција:
    391 
    392 {{{
    393 QA1 ←
     211Во проширена аналитичка нотација се пресметува рангот на книгата во рамки на категоријата:
     212
     213{{{
     214QS1 ←
    394215RANK()
    395216OVER (
    … …  
    397218    ORDER BY vkupen_prihod DESC
    398219)
    399 (QA)
    400 }}}
    401 
    402 Приходот од претходниот достапен квартален запис се добива со:
    403 
    404 {{{
    405 QA2 ←
     220(QS)
     221}}}
     222
     223Приходот од претходниот достапен квартал се добива со:
     224
     225{{{
     226QS2 ←
    406227LAG(vkupen_prihod)
    407228OVER (
    … …  
    409230    ORDER BY kvartal
    410231)
    411 (QA1)
    412 }}}
    413 
    414 Кумулативниот приход се добива со:
    415 
    416 {{{
    417 QA3 ←
    418 CUMULATIVE_SUM(vkupen_prihod)
    419 OVER (
    420     PARTITION BY kniga_id, kategorija_id
    421     ORDER BY kvartal
    422 )
    423 (QA2)
    424 }}}
    425 
    426 Се пресметуваат процентуалното учество и промената на приходот:
    427 
    428 {{{
    429 FA ← π
     232(QS1)
     233}}}
     234
     235Потоа се пресметува процентуалната промена:
     236
     237{{{
     238A ← π
    430239    kvartal,
    431240    kategorija,
    432241    kniga_id,
    433242    naslov,
    434     isbn,
    435243    broj_naracki,
    436244    vkupno_prodadeni,
    437245    vkupen_prihod,
    438     prosecna_prodazna_cena,
    439     broj_prodavani_knigi,
    440     vkupno_prodadeni_kategorija,
    441     vkupen_prihod_kategorija,
    442     prosechen_prihod_po_kniga,
     246    prosecna_cena,
    443247    rang_vo_kategorija,
    444 
    445     (
    446         100 ×
    447         vkupen_prihod /
    448         vkupen_prihod_kategorija
    449     )
    450         → procent_od_prihod_na_kategorija,
    451 
    452248    prihod_prethoden_kvartal,
    453249
    454     (
    455         100 ×
    456         (
    457             vkupen_prihod -
    458             prihod_prethoden_kvartal
    459         )
    460         /
    461         prihod_prethoden_kvartal
    462     )
    463         → promena_prihod_procent,
    464 
    465     kumulativen_prihod
    466 
    467 (QA3)
     250    100 ×
     251    (vkupen_prihod - prihod_prethoden_kvartal)
     252    /
     253    prihod_prethoden_kvartal
     254        → promena_prihod_procent
     255
     256(QS2)
    468257}}}
    469258
    … …  
    475264  kategorija ASC,
    476265  rang_vo_kategorija ASC
    477 (FA)
     266(A)
    478267}}}
    479268
    … …  
    481270=== Објаснување ===
    482271
    483 Извештајот користи повеќе нивоа на обработка.
    484 
    485 Во ''quarterly_book_sales'' податоците од пет релации се поврзуваат и се агрегираат на ниво квартал–книга–категорија.
     272Во првиот дел од прашалникот се поврзуваат пет релации: ''knigi'', ''ima_kategorija'', ''kategorii'', ''sodrzi'' и ''naracki''.
    486273
    487274Со:
    … …  
    491278}}}
    492279
    493 датумите на нарачките се претвораат во квартални периоди.
    494 
    495 За секоја книга се пресметуваат бројот на реализирани нарачки, бројот на продадени примероци, приходот и просечната продажна цена.
    496 
    497 Во ''category_statistics'' се врши второ ниво на агрегација. Податоците кои претходно биле пресметани по книга повторно се агрегираат на ниво квартал–категорија.
    498 
    499 На овој начин може да се спореди индивидуалниот резултат на книгата со резултатите на целата категорија.
     280нарачките се групираат по квартали.
     281
     282За секоја книга во секој квартал се пресметуваат бројот на различни нарачки, бројот на продадени примероци, вкупниот приход и просечната продажна цена.
    500283
    501284Со:
    … …  
    503286{{{
    504287RANK() OVER (
    505     PARTITION BY qbs.kvartal, qbs.kategorija_id
    506     ORDER BY qbs.vkupen_prihod DESC
    507 )
    508 }}}
    509 
    510 секоја книга добива ранг во својата категорија за конкретниот квартал.
    511 
    512 Со ''LAG()'' се добива приходот од претходниот достапен квартален запис за истата книга и категорија.
    513 
    514 Ако книгата нема продажба во некој календарски квартал, тој квартал не создава посебен ред со вредност 0. Поради тоа ''LAG()'' се однесува на претходниот достапен квартален запис.
    515 
    516 Со прозорска ''SUM()'' се пресметува кумулативниот приход на книгата низ кварталите.
    517 
    518 Потоа се пресметуваат процентуалното учество во приходот на категоријата и процентуалната промена во однос на претходниот достапен период.
    519 
    520 Со ''CASE'' трендот се класифицира како ''RAST'', ''PAD'', ''STABILNO'' или ''NEMA PRETHODEN PERIOD''.
    521 
    522 
    523 == Временска анализа на продажбата и прогноза на ризик од исцрпување на залихата ==
     288    PARTITION BY kvartal, kategorija_id
     289    ORDER BY vkupen_prihod DESC
     290)
     291}}}
     292
     293книгите се рангираат според приходот во рамки на нивната категорија.
     294
     295Со ''LAG()'' се добива приходот на истата книга од претходниот достапен квартален период.
     296
     297Потоа се пресметува процентуалната промена на приходот.
     298
     299Со ''CASE'' трендот се класифицира како:
     300
     301* ''RAST'' – приходот е зголемен за повеќе од 10%;
     302* ''PAD'' – приходот е намален за повеќе од 10%;
     303* ''STABILNO'' – промената е во интервал од ±10%;
     304* ''NEMA PRETHODEN PERIOD'' – нема претходен запис за споредба.
     305
     306Со овој извештај може да се следат продажните перформанси на книгите низ повеќе квартали.
     307
     308
     309== Анализа на продажбата и проценка на ризик од исцрпување на залихата ==
    524310
    525311=== Data requirements description ===
    526312
    527 Целта на вториот извештај е да се анализира долгорочната продажна динамика на книгите и врз основа на историската продажба да се направи проценка кои книги имаат најголем ризик од исцрпување на залихата.
    528 
    529 За да не се користи само вкупната историска продажба, реализираните продажби најпрво се агрегираат на месечно ниво.
     313Целта на вториот извештај е врз основа на историската продажба да се процени кои книги имаат најголем ризик наскоро да останат без залиха.
     314
     315Продажбите прво се групираат по книга и месец.
    530316
    531317За секоја книга се анализираат:
    532318
    533 * продажбата во последниот достапен месечен период;
    534 * продажбата во претходниот достапен месечен период;
    535 * приходот во последниот период;
    536 * приходот во претходниот период;
    537 * бројот на различни нарачки;
    538 * подвижниот просек на продажбата над тековниот и најмногу двата претходни достапни месечни записи;
    539 * кумулативниот приход;
     319* продадените примероци по месец;
     320* продажбата од претходниот достапен месечен период;
     321* просечната месечна продажба;
     322* моменталната количина на залиха;
     323* проценетиот број месеци до исцрпување на залихата;
    540324* процентуалната промена на продажбата;
    541 * моменталната залиха;
    542 * проценетиот број на месеци до исцрпување на залихата;
    543 * ниво на ризик;
    544 * глобален ранг според ризикот.
    545 
    546 Подвижниот просек се користи за прогнозата да не зависи само од продажбата во еден период.
    547 
    548 Извештајот може да се користи за планирање на дополнување на залихите и за идентификување на книги чија моментална залиха може брзо да се потроши.
     325* нивото на ризик.
     326
     327Извештајот може да се користи за навремено планирање на дополнувањето на залихата.
    549328
    550329
    … …  
    552331
    553332{{{
    554 WITH monthly_book_sales AS (
     333WITH monthly_sales AS (
    555334    SELECT
    556335        k.kniga_id,
    557336        k.naslov,
    558337
    559         DATE_TRUNC(
    560             'month',
    561             n.datum
    562         ) AS mesec,
     338        DATE_TRUNC('month', n.datum) AS mesec,
     339
     340        SUM(s.kolicina) AS prodadeni,
    563341
    564342        SUM(
    565             s.kolicina
    566         ) AS prodadeni,
    567 
    568         SUM(
    569             s.kolicina *
    570             s.edinechna_cena
    571         ) AS prihod,
    572 
    573         COUNT(
    574             DISTINCT n.naracka_id
    575         ) AS broj_naracki
     343            s.kolicina * s.edinechna_cena
     344        ) AS prihod
    576345
    577346    FROM project.knigi k
    … …  
    588357        k.kniga_id,
    589358        k.naslov,
    590         DATE_TRUNC(
    591             'month',
    592             n.datum
    593         )
     359        DATE_TRUNC('month', n.datum)
    594360),
    595361
    596 sales_with_history AS (
     362sales_analysis AS (
    597363    SELECT
     364        *,
     365
     366        LAG(prodadeni) OVER (
     367            PARTITION BY kniga_id
     368            ORDER BY mesec
     369        ) AS prodadeni_prethoden_mesec,
     370
     371        AVG(prodadeni) OVER (
     372            PARTITION BY kniga_id
     373            ORDER BY mesec
     374            ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
     375        ) AS prosecna_prodazba
     376
     377    FROM monthly_sales
     378),
     379
     380latest_sales AS (
     381    SELECT DISTINCT ON (kniga_id)
    598382        kniga_id,
    599383        naslov,
    … …  
    601385        prodadeni,
    602386        prihod,
    603         broj_naracki,
    604 
    605         LAG(prodadeni) OVER (
    606             PARTITION BY kniga_id
    607             ORDER BY mesec
    608         ) AS prodadeni_prethoden_mesec,
    609 
    610         LAG(prihod) OVER (
    611             PARTITION BY kniga_id
    612             ORDER BY mesec
    613         ) AS prihod_prethoden_mesec,
    614 
    615         AVG(prodadeni) OVER (
    616             PARTITION BY kniga_id
    617             ORDER BY mesec
    618             ROWS BETWEEN
    619                 2 PRECEDING
    620                 AND CURRENT ROW
    621         ) AS podvizen_prosek_prodazba,
    622 
    623         SUM(prihod) OVER (
    624             PARTITION BY kniga_id
    625             ORDER BY mesec
    626             ROWS BETWEEN
    627                 UNBOUNDED PRECEDING
    628                 AND CURRENT ROW
    629         ) AS kumulativen_prihod
    630 
    631     FROM monthly_book_sales
    632 ),
    633 
    634 latest_period AS (
    635     SELECT
    636         *,
    637 
    638         ROW_NUMBER() OVER (
    639             PARTITION BY kniga_id
    640             ORDER BY mesec DESC
    641         ) AS rn
    642 
    643     FROM sales_with_history
    644 ),
    645 
    646 risk_analysis AS (
    647     SELECT
    648         lp.kniga_id,
    649         lp.naslov,
    650         lp.mesec,
    651 
    652         k.kolicina_na_zaliha,
    653 
    654         lp.prodadeni
    655             AS prodadeni_posleden_mesec,
    656 
    657         lp.prodadeni_prethoden_mesec,
    658 
    659         lp.prihod
    660             AS prihod_posleden_mesec,
    661 
    662         lp.prihod_prethoden_mesec,
    663 
    664         lp.broj_naracki,
    665 
    666         lp.podvizen_prosek_prodazba,
    667 
    668         lp.kumulativen_prihod,
    669 
    670         ROUND(
    671             (
    672                 (
    673                     lp.prodadeni -
    674                     lp.prodadeni_prethoden_mesec
    675                 )::numeric
    676                 /
    677                 NULLIF(
    678                     lp.prodadeni_prethoden_mesec,
    679                     0
    680                 )
    681             ) * 100,
    682             2
    683         ) AS rast_prodazba_procent,
    684 
    685         ROUND(
     387        prodadeni_prethoden_mesec,
     388        prosecna_prodazba
     389
     390    FROM sales_analysis
     391
     392    ORDER BY
     393        kniga_id,
     394        mesec DESC
     395)
     396
     397SELECT
     398    ls.kniga_id,
     399    ls.naslov,
     400
     401    TO_CHAR(ls.mesec, 'YYYY-MM') AS posleden_period,
     402
     403    k.kolicina_na_zaliha,
     404
     405    ls.prodadeni AS prodadeni_posleden_period,
     406
     407    ls.prodadeni_prethoden_mesec,
     408
     409    ROUND(
     410        ls.prosecna_prodazba,
     411        2
     412    ) AS prosecna_mesecna_prodazba,
     413
     414    ROUND(
     415        (
     416            (ls.prodadeni - ls.prodadeni_prethoden_mesec)::numeric
     417            /
     418            NULLIF(ls.prodadeni_prethoden_mesec, 0)
     419        ) * 100,
     420        2
     421    ) AS promena_prodazba_procent,
     422
     423    ROUND(
     424        k.kolicina_na_zaliha::numeric
     425        /
     426        NULLIF(ls.prosecna_prodazba, 0),
     427        2
     428    ) AS proceneti_meseci_do_istekuvanje,
     429
     430    CASE
     431        WHEN
    686432            k.kolicina_na_zaliha::numeric
    687433            /
    688             NULLIF(
    689                 lp.podvizen_prosek_prodazba,
    690                 0
    691             ),
    692             2
    693         ) AS proceneti_meseci_do_istekuvanje
    694 
    695     FROM latest_period lp
    696 
    697     JOIN project.knigi k
    698         ON lp.kniga_id = k.kniga_id
    699 
    700     WHERE lp.rn = 1
    701 ),
    702 
    703 final_analysis AS (
    704     SELECT
    705         *,
    706 
    707         CASE
    708             WHEN proceneti_meseci_do_istekuvanje <= 1
    709                  AND COALESCE(
    710                      rast_prodazba_procent,
    711                      0
    712                  ) > 0
    713                 THEN 'KRITICEN RIZIK'
    714 
    715             WHEN proceneti_meseci_do_istekuvanje <= 2
    716                 THEN 'VISOK RIZIK'
    717 
    718             WHEN proceneti_meseci_do_istekuvanje <= 4
    719                 THEN 'SREDEN RIZIK'
    720 
    721             ELSE 'NIZOK RIZIK'
    722         END AS nivo_na_rizik,
    723 
    724         DENSE_RANK() OVER (
    725             ORDER BY
    726                 proceneti_meseci_do_istekuvanje
    727                 ASC NULLS LAST
    728         ) AS rang_rizik
    729 
    730     FROM risk_analysis
    731 )
    732 
    733 SELECT
    734     kniga_id,
    735     naslov,
    736 
    737     TO_CHAR(
    738         mesec,
    739         'YYYY-MM'
    740     ) AS posleden_period,
    741 
    742     kolicina_na_zaliha,
    743 
    744     prodadeni_posleden_mesec,
    745 
    746     prodadeni_prethoden_mesec,
    747 
    748     broj_naracki,
    749 
    750     ROUND(
    751         prihod_posleden_mesec,
    752         2
    753     ) AS prihod_posleden_mesec,
    754 
    755     ROUND(
    756         COALESCE(
    757             prihod_prethoden_mesec,
    758             0
    759         ),
    760         2
    761     ) AS prihod_prethoden_mesec,
    762 
    763     ROUND(
    764         podvizen_prosek_prodazba,
    765         2
    766     ) AS podvizen_prosek_prodazba,
    767 
    768     ROUND(
    769         kumulativen_prihod,
    770         2
    771     ) AS kumulativen_prihod,
    772 
    773     rast_prodazba_procent,
    774 
    775     proceneti_meseci_do_istekuvanje,
    776 
    777     nivo_na_rizik,
    778 
    779     rang_rizik
    780 
    781 FROM final_analysis
     434            NULLIF(ls.prosecna_prodazba, 0) <= 2
     435            THEN 'VISOK RIZIK'
     436
     437        WHEN
     438            k.kolicina_na_zaliha::numeric
     439            /
     440            NULLIF(ls.prosecna_prodazba, 0) <= 4
     441            THEN 'SREDEN RIZIK'
     442
     443        ELSE 'NIZOK RIZIK'
     444    END AS nivo_na_rizik
     445
     446FROM latest_sales ls
     447
     448JOIN project.knigi k
     449    ON ls.kniga_id = k.kniga_id
    782450
    783451ORDER BY
    784     rang_rizik,
    785     naslov;
     452    proceneti_meseci_do_istekuvanje ASC NULLS LAST,
     453    ls.naslov;
    786454}}}
    787455
    … …  
    789457=== Solution Relational Algebra ===
    790458
    791 Најпрво се издвојуваат реализираните нарачки:
     459Прво се издвојуваат реализираните нарачки:
    792460
    793461{{{
    … …  
    795463}}}
    796464
    797 Се поврзуваат книгите, ставките и реализираните нарачки:
     465Книгите се поврзуваат со ставките и нарачките:
    798466
    799467{{{
    … …  
    809477}}}
    810478
    811 Податоците се агрегираат на ниво книга–месец:
    812 
    813 {{{
    814 MBS ←
     479Продажбите се групираат по книга и месец:
     480
     481{{{
     482MS ←
    815483kniga_id,
    816484naslov,
    817 month(datum)→mesec
     485month(datum) → mesec
    818486
    819487γ
    820488
    821 SUM(kolicina)
    822     → prodadeni,
    823 
    824 SUM(kolicina × edinechna_cena)
    825     → prihod,
    826 
    827 COUNT-DISTINCT(naracka_id)
    828     → broj_naracki
     489SUM(kolicina) → prodadeni,
     490SUM(kolicina × edinechna_cena) → prihod
    829491
    830492(R2)
    831493}}}
    832494
    833 Продажбата од претходниот достапен период се добива со:
    834 
    835 {{{
    836 H1 ←
     495Продажбата од претходниот достапен месечен период се добива со:
     496
     497{{{
     498MS1 ←
    837499LAG(prodadeni)
    838500OVER (
    … …  
    840502    ORDER BY mesec
    841503)
    842 (MBS)
    843 }}}
    844 
    845 Приходот од претходниот достапен период се добива со:
    846 
    847 {{{
    848 H2 ←
    849 LAG(prihod)
    850 OVER (
    851     PARTITION BY kniga_id
    852     ORDER BY mesec
    853 )
    854 (H1)
    855 }}}
    856 
    857 Подвижниот просек се пресметува над тековниот и најмногу двата претходни достапни месечни записи:
    858 
    859 {{{
    860 H3 ←
     504(MS)
     505}}}
     506
     507Просечната продажба од тековниот и најмногу двата претходни достапни периоди се пресметува со:
     508
     509{{{
     510MS2 ←
    861511MOVING_AVG(prodadeni)
    862512OVER (
    863513    PARTITION BY kniga_id
    864514    ORDER BY mesec
    865     ROWS BETWEEN
    866         2 PRECEDING
    867         AND CURRENT ROW
    868 )
    869 (H2)
    870 }}}
    871 
    872 Кумулативниот приход се пресметува од првиот достапен период до тековниот:
    873 
    874 {{{
    875 H4 ←
    876 CUMULATIVE_SUM(prihod)
    877 OVER (
    878     PARTITION BY kniga_id
    879     ORDER BY mesec
    880 )
    881 (H3)
    882 }}}
    883 
    884 Записите се рангираат обратно хронолошки:
    885 
    886 {{{
    887 H5 ←
    888 ROW_NUMBER()
    889 OVER (
    890     PARTITION BY kniga_id
    891     ORDER BY mesec DESC
    892 )
    893 (H4)
    894 }}}
    895 
    896 Се задржува најновиот достапен период за секоја книга:
    897 
    898 {{{
    899 LATEST ← σ rn=1 (H5)
    900 }}}
    901 
    902 Се додава моменталната залиха:
    903 
    904 {{{
    905 RB ←
     515    ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
     516)
     517(MS1)
     518}}}
     519
     520За секоја книга се избира најновиот достапен период:
     521
     522{{{
     523LATEST ←
     524LATEST_BY(mesec)
     525GROUP BY kniga_id
     526(MS2)
     527}}}
     528
     529Резултатот се поврзува со книгите за да се добие моменталната залиха:
     530
     531{{{
     532RISK ←
    906533LATEST
    907534⋈ LATEST.kniga_id = KNIGI.kniga_id
    … …  
    909536}}}
    910537
    911 Се пресметуваат промената на продажбата и проценетото време до исцрпување:
    912 
    913 {{{
    914 RA ← π
     538Се пресметуваат процентуалната промена и проценетото време до исцрпување:
     539
     540{{{
     541A ← π
    915542    kniga_id,
    916543    naslov,
    … …  
    919546    prodadeni,
    920547    prodadeni_prethoden_mesec,
    921     prihod,
    922     prihod_prethoden_mesec,
    923     broj_naracki,
    924     podvizen_prosek_prodazba,
    925     kumulativen_prihod,
    926 
    927     (
    928         100 ×
    929         (
    930             prodadeni -
    931             prodadeni_prethoden_mesec
    932         )
    933         /
    934         prodadeni_prethoden_mesec
    935     )
    936         → rast_prodazba_procent,
    937 
    938     (
    939         kolicina_na_zaliha /
    940         podvizen_prosek_prodazba
    941     )
     548    prosecna_prodazba,
     549
     550    100 ×
     551    (prodadeni - prodadeni_prethoden_mesec)
     552    /
     553    prodadeni_prethoden_mesec
     554        → promena_prodazba_procent,
     555
     556    kolicina_na_zaliha
     557    /
     558    prosecna_prodazba
    942559        → proceneti_meseci_do_istekuvanje
    943560
    944 (RB)
    945 }}}
    946 
    947 Со условна проширена проекција се определува нивото на ризик.
    948 
    949 Потоа книгите се рангираат според проценетото време до исцрпување:
    950 
    951 {{{
    952 RR ←
    953 DENSE_RANK()
    954 OVER (
    955     ORDER BY
    956     proceneti_meseci_do_istekuvanje ASC
    957 )
    958 (RA)
    959 }}}
    960 
    961 Конечниот резултат е:
     561(RISK)
     562}}}
     563
     564Конечниот резултат се подредува од книгите со најголем ризик кон книгите со помал ризик:
    962565
    963566{{{
    964567RESULT ←
    965 τ rang_rizik ASC,
    966   naslov ASC
    967 (RR)
     568τ proceneti_meseci_do_istekuvanje ASC
     569(A)
    968570}}}
    969571
    … …  
    971573=== Објаснување ===
    972574
    973 Во ''monthly_book_sales'' реализираните продажби се агрегираат на месечно ниво.
     575Во ''monthly_sales'' продажбите се групираат по книга и месец.
    974576
    975577Со:
    … …  
    979581}}}
    980582
    981 се формира временска серија за секоја книга.
    982 
    983 За секој достапен месечен период се пресметуваат бројот на продадени примероци, приходот и бројот на различни реализирани нарачки.
    984 
    985 Во ''sales_with_history'' се користи ''LAG()'' за добивање на продажбата и приходот од претходниот достапен период.
    986 
    987 Дополнително се пресметува подвижен просек:
     583се добива месечна временска анализа.
     584
     585За секој месец се пресметуваат бројот на продадени примероци и остварениот приход.
     586
     587Со ''LAG()'' се добива продажбата од претходниот достапен месечен период.
     588
     589Со:
    988590
    989591{{{
    … …  
    995597}}}
    996598
    997 Овој показател ја зема предвид продажбата од тековниот и најмногу двата претходни достапни месечни записи.
    998 
    999 Поради тоа проценката на залихата е помалку зависна од евентуално невообичаено висока или ниска продажба во само еден период.
    1000 
    1001 Со:
    1002 
    1003 {{{
    1004 SUM(prihod) OVER (
    1005     PARTITION BY kniga_id
    1006     ORDER BY mesec
    1007     ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    1008 )
    1009 }}}
    1010 
    1011 се добива кумулативниот приход.
    1012 
    1013 Во ''latest_period'' со ''ROW_NUMBER()'' се идентификува последниот достапен период за секоја книга.
    1014 
    1015 Потоа резултатот се поврзува со ''knigi'' за да се добие моменталната залиха.
    1016 
    1017 Проценетото време до исцрпување се пресметува како однос меѓу моменталната залиха и подвижниот просек на продажбата.
    1018 
    1019 ''NULLIF'' спречува делење со нула.
    1020 
    1021 Со ''CASE'' книгите се класифицираат во различни нивоа на ризик, а со ''DENSE_RANK()'' се рангираат според проценетата итност за дополнување на залихата.
    1022 
    1023 Важно е дека ''LAG()'' го враќа претходниот достапен месечен запис. Ако во одреден календарски месец нема реализирана продажба за книгата, тој месец не се појавува како посебен ред со продажба 0.
    1024 
    1025 
    1026 == Финална дискусија ==
    1027 
    1028 Двата извештаи се наменети за долгорочна аналитичка обработка на податоците во !BiblioPremium.
    1029 
    1030 Првиот извештај се фокусира на кварталните продажни перформанси. Тој комбинира анализа на книга, категорија и временски период и овозможува споредување на тековниот резултат со претходните периоди.
    1031 
    1032 Со него може да се идентификуваат книгите кои генерираат најголем дел од приходот на категоријата, да се следи нивниот ранг и да се анализира дали приходот расте, опаѓа или останува релативно стабилен.
    1033 
    1034 Вториот извештај има прогнозна цел. Историската продажба се анализира како временска серија и се користи за проценка на ризикот од исцрпување на моменталната залиха.
    1035 
    1036 Во двата извештаи се користат повеќе напредни SQL механизми:
    1037 
    1038 * CTE (Common Table Expressions);
     599се пресметува просекот на продажбата од тековниот и најмногу двата претходни достапни периоди.
     600
     601Овој просек се користи како основа за проценка на идната потрошувачка на залихата.
     602
     603Во ''latest_sales'' се задржува последниот достапен период за секоја книга.
     604
     605Потоа податоците се поврзуваат со ''knigi'' за да се добие моменталната залиха.
     606
     607Проценетото време до исцрпување се пресметува како:
     608
     609{{{
     610моментална залиха / просечна месечна продажба
     611}}}
     612
     613Со ''CASE'' книгите се делат во три групи:
     614
     615* ''VISOK RIZIK'' – залихата се проценува дека ќе трае најмногу 2 месеци;
     616* ''SREDEN RIZIK'' – залихата се проценува дека ќе трае најмногу 4 месеци;
     617* ''NIZOK RIZIK'' – залихата се проценува дека ќе трае повеќе од 4 месеци.
     618
     619''NULLIF'' се користи за да се избегне делење со нула.
     620
     621На овој начин извештајот не ја прикажува само моменталната залиха, туку ја поврзува со историската динамика на продажбата.
     622
     623
     624== Заклучок ==
     625
     626Првиот извештај овозможува квартална анализа на продажните перформанси на книгите во рамки на нивните категории и споредување со претходните периоди.
     627
     628Вториот извештај ја анализира месечната продажба и ја користи историската динамика за проценка на ризикот од исцрпување на залихата.
     629
     630Во извештаите се користат:
     631
    1039632* повеќекратни JOIN операции;
    1040 * повеќестепено агрегирање;
     633* CTE изрази;
    1041634* COUNT(DISTINCT ...);
    1042635* SUM и AVG;
     636* GROUP BY;
    1043637* DATE_TRUNC;
    1044638* RANK();
    1045 * DENSE_RANK();
    1046639* LAG();
    1047 * ROW_NUMBER();
    1048640* PARTITION BY;
    1049641* прозорски функции;
    1050 * window frame со ROWS BETWEEN;
    1051 * кумулативни пресметки;
    1052642* подвижен просек;
    1053643* CASE;
    1054644* NULLIF;
    1055645* COALESCE;
    1056 * процентуални показатели;
    1057 * квартална анализа;
    1058 * месечна анализа;
    1059 * споредување со претходни периоди;
    1060 * рангирање;
    1061 * проценка на идно исцрпување на залиха.
    1062 
    1063 Со тоа извештаите не прикажуваат само податоци кои директно се наоѓаат во базата, туку од постојните трансакциски податоци изведуваат дополнителни информации за долгорочните продажни перформанси и идните потреби за залиха.
     646* процентуални пресметки;
     647* квартална и месечна анализа.
     648
     649Со тоа двата извештаи обезбедуваат податоци кои можат да се користат за анализа на долгорочното работење на !BiblioPremium и за донесување одлуки поврзани со продажбата и залихите.