| 6 | | - `v_staff_daily_schedule`: Го прикажува дневниот работен распоред за секој вработен и е наменет за користење од страна на самите вработени и рецепционерите. |
| 7 | | - `v_staff_open_slots`: Ги враќа сите слободни термини од по 15 минути во наредните 30 дена за секој активен вработен. |
| 8 | | - `v_companies_by_category`: Се користи за филтрирање на компании и салони кои нудат одредена услуга или припаѓаат во категорија од интерес на клиентот. |
| 9 | | - `v_staff_service_menu`: Ги прикажува сите услуги кои одреден вработен може да ги понуди, заедно со неговата просечна оценка и бројот на извршени услуги. |
| 10 | | - `v_monthly_revenue_by_company`: Претставува месечен аналитички финансиски извештај за приходите на одредена компанија, наменет за сопствениците на салоните. |
| 11 | | - `v_future_appointments_client_o`: Ги прикажува сите идни закажани термини за одреден клиент, заедно со детали за вработениот, услугите и локацијата на салонот. |
| 12 | | - `v_client_dashboard`: Го прикажува профилот на клиентот по неговата најава, вклучувајќи поени за лојалност, следниот термин и потрошените пари во последните 30 дена. |
| 13 | | - `v_invoice_detail_o`: Прикажува детална сметка по завршен термин со информации за плаќање, промо кодови, извршени услуги и податоци за клиентот и вработениот. |
| 14 | | - `v_staff_profile_dashboard`: Овозможува детален преглед на профилот на вработениот, неговата специјалност, улогите во системот и менаџирањето на неговиот работен календар. |
| | 6 | |
| | 7 | == v_staff_daily_schedule |
| | 8 | |
| | 9 | Овој view служи за приказ на дневниот распоред на вработените. |
| | 10 | |
| | 11 | Табелата `appointment` е главната табела бидејќи ги содржи сите информации за закажаните термини. |
| | 12 | |
| | 13 | Се спојуваат: |
| | 14 | |
| | 15 | * `user` за име на вработениот. |
| | 16 | * `staff` за локацијата. |
| | 17 | * `company_location` за адресата. |
| | 18 | * `client` и `user` за информации за клиентот. |
| | 19 | |
| | 20 | Се користат два `LATERAL JOIN`: |
| | 21 | |
| | 22 | * Првиот ги агрегира сите улоги на вработениот од `staff_type`. |
| | 23 | * Вториот ги агрегира сите услуги поврзани со терминот од `appointment_service`. |
| | 24 | |
| | 25 | Филтерот: |
| | 26 | |
| | 27 | {{{ |
| | 28 | WHERE status <> 'cancelled' |
| | 29 | AND status <> 'completed' |
| | 30 | }}} |
| | 31 | |
| | 32 | се извршува најрано со што значително се намалува бројот на обработени термини. |
| | 33 | |
| | 34 | Функцијата `LEAD()` пресметува временски јаз помеѓу два последователни термини без дополнителни self-join операции. |
| | 35 | |
| | 36 | --- |
| | 37 | |
| | 38 | == v_staff_open_slots |
| | 39 | |
| | 40 | Овој view ги враќа сите слободни термини за закажување. |
| | 41 | |
| | 42 | Најпрво се креираат три мали агрегирани множества: |
| | 43 | |
| | 44 | * `staff_roles` |
| | 45 | * `staff_services` |
| | 46 | * `staff_rating` |
| | 47 | |
| | 48 | Со ова агрегирањето се извршува само еднаш. |
| | 49 | |
| | 50 | Главната табела е `staff_time_slot`. |
| | 51 | |
| | 52 | Филтрите: |
| | 53 | |
| | 54 | {{{ |
| | 55 | appointment_id IS NULL |
| | 56 | slot_start >= NOW() |
| | 57 | slot_start < NOW() + INTERVAL '30 days' |
| | 58 | }}} |
| | 59 | |
| | 60 | се применуваат веднаш. |
| | 61 | |
| | 62 | Потоа се прави JOIN со: |
| | 63 | |
| | 64 | * `staff` |
| | 65 | * `user` |
| | 66 | * `company_location` |
| | 67 | |
| | 68 | и LEFT JOIN со: |
| | 69 | |
| | 70 | * `blocked_time` |
| | 71 | |
| | 72 | за елиминација на блокираните термини. |
| | 73 | |
| | 74 | Со условот: |
| | 75 | |
| | 76 | {{{ |
| | 77 | b.block_id IS NULL |
| | 78 | }}} |
| | 79 | |
| | 80 | се задржуваат само реално достапните слотови. |
| | 81 | |
| | 82 | --- |
| | 83 | |
| | 84 | == v_companies_by_category |
| | 85 | |
| | 86 | Овој view овозможува пребарување компании според категорија и услуги. |
| | 87 | |
| | 88 | CTE `company_services` прво ги агрегира сите активни услуги по компанија. |
| | 89 | |
| | 90 | Филтерот: |
| | 91 | |
| | 92 | {{{ |
| | 93 | WHERE s.is_active = TRUE |
| | 94 | }}} |
| | 95 | |
| | 96 | се применува пред агрегацијата. |
| | 97 | |
| | 98 | Потоа се приклучуваат: |
| | 99 | |
| | 100 | * `company_company_category` |
| | 101 | * `company_category` |
| | 102 | * `company` |
| | 103 | |
| | 104 | На овој начин главниот SELECT работи со значително помал број редови. |
| | 105 | |
| | 106 | --- |
| | 107 | |
| | 108 | == v_staff_service_menu |
| | 109 | |
| | 110 | Овој view прикажува кои услуги ги нуди секој вработен. |
| | 111 | |
| | 112 | Во CTE `staff_service_ratings` однапред се пресметуваат: |
| | 113 | |
| | 114 | * просечна оцена |
| | 115 | * број на рецензии |
| | 116 | * број на извршувања |
| | 117 | |
| | 118 | Само термините со статус: |
| | 119 | |
| | 120 | {{{ |
| | 121 | completed |
| | 122 | }}} |
| | 123 | |
| | 124 | учествуваат во пресметката. |
| | 125 | |
| | 126 | Ова значително ја намалува количината на податоци бидејќи не се анализираат активни или откажани термини. |
| | 127 | |
| | 128 | --- |
| | 129 | |
| | 130 | == v_monthly_revenue_by_company |
| | 131 | |
| | 132 | Овој view служи за финансиски извештаи. |
| | 133 | |
| | 134 | Се користат само табелите: |
| | 135 | |
| | 136 | * `invoice` |
| | 137 | * `appointment` |
| | 138 | * `company_location` |
| | 139 | * `company` |
| | 140 | |
| | 141 | Бидејќи `invoice` е значително помала од `appointment_service`, пресметката е многу поефикасна. |
| | 142 | |
| | 143 | Сите финансиски агрегати: |
| | 144 | |
| | 145 | * SUM |
| | 146 | * AVG |
| | 147 | * COUNT |
| | 148 | |
| | 149 | се пресметуваат во една единствена GROUP BY операција. |
| | 150 | |
| | 151 | --- |
| | 152 | |
| | 153 | == v_future_appointments_client_o |
| | 154 | |
| | 155 | Овој view ги враќа идните термини на клиентите. |
| | 156 | |
| | 157 | Филтерот: |
| | 158 | |
| | 159 | {{{ |
| | 160 | appointment_date >= CURRENT_DATE |
| | 161 | status <> 'cancelled' |
| | 162 | }}} |
| | 163 | |
| | 164 | се применува уште на почетокот. |
| | 165 | |
| | 166 | Со тоа се елиминираат сите историски записи. |
| | 167 | |
| | 168 | Се користи `LATERAL JOIN` за агрегација на услугите на секој термин поединечно наместо глобално GROUP BY врз целата табела `appointment_service`. |
| | 169 | |
| | 170 | За овој view е креиран индекс: |
| | 171 | |
| | 172 | {{{ |
| | 173 | idx_appointment_client_future |
| | 174 | }}} |
| | 175 | |
| | 176 | бидејќи пребарувањето најчесто се врши според клиент и датум. |
| | 177 | |
| | 178 | --- |
| | 179 | |
| | 180 | == v_client_dashboard |
| | 181 | |
| | 182 | Овој view е наменет за почетниот екран на клиентот. |
| | 183 | |
| | 184 | Се користат две CTE структури: |
| | 185 | |
| | 186 | * `upcoming` |
| | 187 | * `recent_spend` |
| | 188 | |
| | 189 | Тие однапред ги пресметуваат: |
| | 190 | |
| | 191 | * идните термини |
| | 192 | * потрошувачката во последните 30 дена |
| | 193 | |
| | 194 | Потоа главниот SELECT само ги приклучува готовите агрегирани резултати. |
| | 195 | |
| | 196 | Ова е поефикасно отколку секој пат да се пресметуваат агрегатите за секој клиент одново. |
| | 197 | |
| | 198 | --- |
| | 199 | |
| | 200 | == mv_staff_avg_rating |
| | 201 | |
| | 202 | Ова е Materialized View. |
| | 203 | |
| | 204 | Наместо просечниот рејтинг да се пресметува секој пат кога се отвора профил на вработен, резултатот однапред се чува физички во базата. |
| | 205 | |
| | 206 | Предности: |
| | 207 | |
| | 208 | * многу побрзо читање |
| | 209 | * помал број JOIN операции |
| | 210 | * помал CPU трошок |
| | 211 | |
| | 212 | Се освежува преку: |
| | 213 | |
| | 214 | {{{ |
| | 215 | REFRESH MATERIALIZED VIEW CONCURRENTLY |
| | 216 | }}} |
| | 217 | |
| | 218 | што овозможува истовремено користење на податоците. |
| | 219 | |
| | 220 | --- |
| | 221 | |
| | 222 | == v_staff_profile_m |
| | 223 | |
| | 224 | Овој view прикажува целосен профил на вработен. |
| | 225 | |
| | 226 | Наместо повторно да се пресметуваат оценки од `review`, се користи: |
| | 227 | |
| | 228 | {{{ |
| | 229 | mv_staff_avg_rating |
| | 230 | }}} |
| | 231 | |
| | 232 | што значително го намалува времето на извршување. |
| | 233 | |
| | 234 | Дополнително се користат два `LATERAL JOIN`: |
| | 235 | |
| | 236 | * агрегирање на услуги |
| | 237 | * агрегирање на улоги |
| | 238 | |
| | 239 | Само активни корисници учествуваат во резултатот: |
| | 240 | |
| | 241 | {{{ |
| | 242 | WHERE u.is_active = TRUE |
| | 243 | }}} |
| | 244 | |
| | 245 | --- |
| | 246 | |
| | 247 | == v_invoice_detail_o |
| | 248 | |
| | 249 | Овој view е најдеталниот финансиски поглед. |
| | 250 | |
| | 251 | Главната табела е `invoice`, бидејќи фактурите се значително помалку од сите термини и услуги во системот. |
| | 252 | |
| | 253 | Се користат три `LATERAL JOIN`: |
| | 254 | |
| | 255 | * агрегација на услуги од терминот |
| | 256 | * агрегација на промо кодови |
| | 257 | * агрегација на улоги на вработениот |
| | 258 | |
| | 259 | Со ова секоја агрегација се извршува само за конкретната фактура. |
| | 260 | |
| | 261 | Овој пристап е поефикасен од глобални GROUP BY операции над целата база. |
| | 262 | |
| | 263 | --- |
| | 264 | |
| | 265 | == Индекси |
| | 266 | |
| | 267 | Во решението се користи минимален број индекси: |
| | 268 | |
| | 269 | * `idx_appointment_client_future` |
| | 270 | * индекс над `mv_staff_avg_rating` |
| | 271 | * `idx_appointment_staff_rating` |
| | 272 | |
| | 273 | Целта е да се избегне прекумерно индексирање кое би ја забавило работата при INSERT, UPDATE и DELETE операции. |
| | 274 | |
| | 275 | Избраните индекси покриваат само најчестите пребарувања: |
| | 276 | |
| | 277 | * идни термини по клиент |
| | 278 | * рејтинзи по вработен |
| | 279 | * профил на вработен |
| | 280 | |
| | 281 | Со ова се постигнува баланс помеѓу брзина на читање и брзина на запишување на податоци. |