| | 250 | == Views == |
| | 251 | |
| | 252 | За почесто користените прикази и аналитички податоци се дефинирани PostgreSQL views. Тие ги обединуваат податоците од повеќе поврзани табели и овозможуваат поедноставен пристап до информации за проекти, договори, буџети, оценки, спорови и претплати. |
| | 253 | |
| | 254 | Целосната скрипта е достапна во: |
| | 255 | |
| | 256 | * [attachment:views.sql views.sql] |
| | 257 | |
| | 258 | === Проекти по Vendor и Client === |
| | 259 | |
| | 260 | Погледот `vw_projects_per_vendor` ги прикажува сите проекти поврзани со одреден vendor, заедно со статусот, периодот и буџетот: |
| | 261 | |
| | 262 | {{{#!sql |
| | 263 | CREATE OR REPLACE VIEW vw_projects_per_vendor AS |
| | 264 | SELECT v.vendor_id, |
| | 265 | v.agency_name, |
| | 266 | p.project_id, |
| | 267 | p.project_name, |
| | 268 | ps.status_name, |
| | 269 | p.start_date, |
| | 270 | p.end_date, |
| | 271 | p.budget, |
| | 272 | cvc.currency_code |
| | 273 | FROM Project p |
| | 274 | JOIN Client_Vendor_Contract cvc |
| | 275 | ON cvc.contract_id = p.contract_id |
| | 276 | JOIN Vendor v |
| | 277 | ON v.vendor_id = cvc.vendor_id |
| | 278 | JOIN Project_Status ps |
| | 279 | ON ps.status_id = p.status_id |
| | 280 | ORDER BY v.agency_name, ps.status_name, p.project_name; |
| | 281 | }}} |
| | 282 | |
| | 283 | Соодветниот поглед за клиентите е `vw_projects_per_client`: |
| | 284 | |
| | 285 | {{{#!sql |
| | 286 | CREATE OR REPLACE VIEW vw_projects_per_client AS |
| | 287 | SELECT c.client_id, |
| | 288 | c.company_name, |
| | 289 | p.project_id, |
| | 290 | p.project_name, |
| | 291 | ps.status_name, |
| | 292 | p.start_date, |
| | 293 | p.end_date, |
| | 294 | p.budget, |
| | 295 | cvc.currency_code |
| | 296 | FROM Project p |
| | 297 | JOIN Client_Vendor_Contract cvc |
| | 298 | ON cvc.contract_id = p.contract_id |
| | 299 | JOIN Client c |
| | 300 | ON c.client_id = cvc.client_id |
| | 301 | JOIN Project_Status ps |
| | 302 | ON ps.status_id = p.status_id |
| | 303 | ORDER BY c.company_name, ps.status_name, p.project_name; |
| | 304 | }}} |
| | 305 | |
| | 306 | === Буџети по Vendor и Client === |
| | 307 | |
| | 308 | За аналитички приказ на вкупниот број на проекти и нивниот буџет се користат `vw_budget_per_vendor` и `vw_budget_per_client`. |
| | 309 | |
| | 310 | {{{#!sql |
| | 311 | CREATE OR REPLACE VIEW vw_budget_per_vendor AS |
| | 312 | SELECT v.vendor_id, |
| | 313 | v.agency_name, |
| | 314 | cvc.currency_code, |
| | 315 | COUNT(p.project_id) AS project_count, |
| | 316 | SUM(p.budget) AS total_budget |
| | 317 | FROM Project p |
| | 318 | JOIN Client_Vendor_Contract cvc |
| | 319 | ON cvc.contract_id = p.contract_id |
| | 320 | JOIN Vendor v |
| | 321 | ON v.vendor_id = cvc.vendor_id |
| | 322 | GROUP BY v.vendor_id, v.agency_name, cvc.currency_code |
| | 323 | ORDER BY v.agency_name, cvc.currency_code; |
| | 324 | }}} |
| | 325 | |
| | 326 | {{{#!sql |
| | 327 | CREATE OR REPLACE VIEW vw_budget_per_client AS |
| | 328 | SELECT c.client_id, |
| | 329 | c.company_name, |
| | 330 | cvc.currency_code, |
| | 331 | COUNT(p.project_id) AS project_count, |
| | 332 | SUM(p.budget) AS total_budget |
| | 333 | FROM Project p |
| | 334 | JOIN Client_Vendor_Contract cvc |
| | 335 | ON cvc.contract_id = p.contract_id |
| | 336 | JOIN Client c |
| | 337 | ON c.client_id = cvc.client_id |
| | 338 | GROUP BY c.client_id, c.company_name, cvc.currency_code |
| | 339 | ORDER BY c.company_name, cvc.currency_code; |
| | 340 | }}} |
| | 341 | |
| | 342 | Групирањето се врши и според `currency_code`, со што буџетите во различни валути не се собираат во една вредност. |
| | 343 | |
| | 344 | === Клиенти по индустрија === |
| | 345 | |
| | 346 | `vw_clients_per_industry` овозможува приказ на клиентските компании групирани според нивната индустрија: |
| | 347 | |
| | 348 | {{{#!sql |
| | 349 | CREATE OR REPLACE VIEW vw_clients_per_industry AS |
| | 350 | SELECT i.industry_id, |
| | 351 | i.industry_name, |
| | 352 | c.client_id, |
| | 353 | c.company_name, |
| | 354 | c.contact_email |
| | 355 | FROM Client c |
| | 356 | JOIN Industry i |
| | 357 | ON i.industry_id = c.industry_id |
| | 358 | ORDER BY i.industry_name, c.company_name; |
| | 359 | }}} |
| | 360 | |
| | 361 | === Просечна оценка по Vendor === |
| | 362 | |
| | 363 | За секој vendor се пресметува просечна оценка од сите `Review_Score` записи за неговите проекти: |
| | 364 | |
| | 365 | {{{#!sql |
| | 366 | CREATE OR REPLACE VIEW vw_avg_rating_per_vendor AS |
| | 367 | SELECT v.vendor_id, |
| | 368 | v.agency_name, |
| | 369 | COUNT(DISTINCT r.review_id) AS review_count, |
| | 370 | ROUND(AVG(rs.score_value), 2) AS avg_rating |
| | 371 | FROM Review_Score rs |
| | 372 | JOIN Review r |
| | 373 | ON r.review_id = rs.review_id |
| | 374 | JOIN Project p |
| | 375 | ON p.project_id = r.project_id |
| | 376 | JOIN Client_Vendor_Contract cvc |
| | 377 | ON cvc.contract_id = p.contract_id |
| | 378 | JOIN Vendor v |
| | 379 | ON v.vendor_id = cvc.vendor_id |
| | 380 | GROUP BY v.vendor_id, v.agency_name |
| | 381 | ORDER BY avg_rating DESC NULLS LAST; |
| | 382 | }}} |
| | 383 | |
| | 384 | `COUNT(DISTINCT r.review_id)` го прикажува бројот на рецензии, додека `AVG` ја пресметува просечната вредност од сите оценети димензии. |
| | 385 | |
| | 386 | === Нерешени Dispute Tickets === |
| | 387 | |
| | 388 | За потребите на dispute системот е креиран `vw_unresolved_dispute_tickets`, кој ги прикажува само тикетите што сè уште не се решени: |
| | 389 | |
| | 390 | {{{#!sql |
| | 391 | CREATE OR REPLACE VIEW vw_unresolved_dispute_tickets AS |
| | 392 | SELECT dt.ticket_id, |
| | 393 | dt.filed_at, |
| | 394 | dt.reason, |
| | 395 | r.review_id, |
| | 396 | p.project_id, |
| | 397 | p.project_name, |
| | 398 | vu.user_id AS filed_by_vendor_user_id, |
| | 399 | vu_u.first_name || ' ' || vu_u.last_name |
| | 400 | AS filed_by_vendor_user, |
| | 401 | mu.user_id AS assigned_management_user_id, |
| | 402 | mu_u.first_name || ' ' || mu_u.last_name |
| | 403 | AS assigned_to_management_user, |
| | 404 | dt.created_at, |
| | 405 | dt.updated_at |
| | 406 | FROM Dispute_Ticket dt |
| | 407 | JOIN Review r |
| | 408 | ON r.review_id = dt.review_id |
| | 409 | JOIN Project p |
| | 410 | ON p.project_id = r.project_id |
| | 411 | JOIN Vendor_User vu |
| | 412 | ON vu.user_id = dt.vendor_user_id |
| | 413 | JOIN "User" vu_u |
| | 414 | ON vu_u.user_id = vu.user_id |
| | 415 | LEFT JOIN Management_User mu |
| | 416 | ON mu.user_id = dt.assigned_management_user_id |
| | 417 | LEFT JOIN "User" mu_u |
| | 418 | ON mu_u.user_id = mu.user_id |
| | 419 | WHERE dt.is_resolved = false |
| | 420 | ORDER BY dt.filed_at; |
| | 421 | }}} |
| | 422 | |
| | 423 | За management корисникот се користи `LEFT JOIN`, бидејќи нерешен dispute ticket може сè уште да нема доделен management корисник. |
| | 424 | |
| | 425 | === Број на проекти по статус === |
| | 426 | |
| | 427 | За статистички приказ на состојбата на проектите се користат два погледи кои го пресметуваат бројот на проекти по статус. |
| | 428 | |
| | 429 | За vendor: |
| | 430 | |
| | 431 | {{{#!sql |
| | 432 | CREATE OR REPLACE VIEW vw_project_count_by_status_per_vendor AS |
| | 433 | SELECT v.vendor_id, |
| | 434 | v.agency_name, |
| | 435 | ps.status_id, |
| | 436 | ps.status_name, |
| | 437 | COUNT(p.project_id) AS project_count |
| | 438 | FROM Project p |
| | 439 | JOIN Client_Vendor_Contract cvc |
| | 440 | ON cvc.contract_id = p.contract_id |
| | 441 | JOIN Vendor v |
| | 442 | ON v.vendor_id = cvc.vendor_id |
| | 443 | JOIN Project_Status ps |
| | 444 | ON ps.status_id = p.status_id |
| | 445 | GROUP BY v.vendor_id, |
| | 446 | v.agency_name, |
| | 447 | ps.status_id, |
| | 448 | ps.status_name |
| | 449 | ORDER BY v.agency_name, ps.status_name; |
| | 450 | }}} |
| | 451 | |
| | 452 | За client: |
| | 453 | |
| | 454 | {{{#!sql |
| | 455 | CREATE OR REPLACE VIEW vw_project_count_by_status_per_client AS |
| | 456 | SELECT c.client_id, |
| | 457 | c.company_name, |
| | 458 | ps.status_id, |
| | 459 | ps.status_name, |
| | 460 | COUNT(p.project_id) AS project_count |
| | 461 | FROM Project p |
| | 462 | JOIN Client_Vendor_Contract cvc |
| | 463 | ON cvc.contract_id = p.contract_id |
| | 464 | JOIN Client c |
| | 465 | ON c.client_id = cvc.client_id |
| | 466 | JOIN Project_Status ps |
| | 467 | ON ps.status_id = p.status_id |
| | 468 | GROUP BY c.client_id, |
| | 469 | c.company_name, |
| | 470 | ps.status_id, |
| | 471 | ps.status_name |
| | 472 | ORDER BY c.company_name, ps.status_name; |
| | 473 | }}} |
| | 474 | |
| | 475 | Овие погледи овозможуваат брзо добивање на бројот на проекти во статуси како `Draft`, `In Progress`, `Completed` и останатите дефинирани статуси. |
| | 476 | |
| | 477 | === Договори по Vendor и Client === |
| | 478 | |
| | 479 | За приказ на договорите од двете перспективи се користат `vw_contracts_per_vendor` и `vw_contracts_per_client`. |
| | 480 | |
| | 481 | {{{#!sql |
| | 482 | CREATE OR REPLACE VIEW vw_contracts_per_vendor AS |
| | 483 | SELECT v.vendor_id, |
| | 484 | v.agency_name, |
| | 485 | cvc.contract_id, |
| | 486 | cvc.contract_number, |
| | 487 | cvc.contract_title, |
| | 488 | c.client_id, |
| | 489 | c.company_name AS client_name, |
| | 490 | cvc.start_date, |
| | 491 | cvc.end_date, |
| | 492 | cvc.total_value, |
| | 493 | cvc.currency_code, |
| | 494 | cvc.is_active |
| | 495 | FROM Client_Vendor_Contract cvc |
| | 496 | JOIN Vendor v |
| | 497 | ON v.vendor_id = cvc.vendor_id |
| | 498 | JOIN Client c |
| | 499 | ON c.client_id = cvc.client_id |
| | 500 | ORDER BY v.agency_name, |
| | 501 | cvc.is_active DESC, |
| | 502 | cvc.start_date DESC; |
| | 503 | }}} |
| | 504 | |
| | 505 | {{{#!sql |
| | 506 | CREATE OR REPLACE VIEW vw_contracts_per_client AS |
| | 507 | SELECT c.client_id, |
| | 508 | c.company_name, |
| | 509 | cvc.contract_id, |
| | 510 | cvc.contract_number, |
| | 511 | cvc.contract_title, |
| | 512 | v.vendor_id, |
| | 513 | v.agency_name AS vendor_name, |
| | 514 | cvc.start_date, |
| | 515 | cvc.end_date, |
| | 516 | cvc.total_value, |
| | 517 | cvc.currency_code, |
| | 518 | cvc.is_active |
| | 519 | FROM Client_Vendor_Contract cvc |
| | 520 | JOIN Client c |
| | 521 | ON c.client_id = cvc.client_id |
| | 522 | JOIN Vendor v |
| | 523 | ON v.vendor_id = cvc.vendor_id |
| | 524 | ORDER BY c.company_name, |
| | 525 | cvc.is_active DESC, |
| | 526 | cvc.start_date DESC; |
| | 527 | }}} |
| | 528 | |
| | 529 | Со сортирање на `is_active DESC`, активните договори се прикажуваат пред историските договори. |
| | 530 | |
| | 531 | === Vendor претплати === |
| | 532 | |
| | 533 | За приказ на активните и историските претплати на агенциите е дефиниран `vw_vendor_subscriptions`: |
| | 534 | |
| | 535 | {{{#!sql |
| | 536 | CREATE OR REPLACE VIEW vw_vendor_subscriptions AS |
| | 537 | SELECT v.vendor_id, |
| | 538 | v.agency_name, |
| | 539 | st.tier_id, |
| | 540 | st.tier_name, |
| | 541 | COALESCE( |
| | 542 | vs.negotiated_price, |
| | 543 | st.list_price, |
| | 544 | 0 |
| | 545 | ) AS effective_price, |
| | 546 | vs.start_date, |
| | 547 | vs.end_date, |
| | 548 | vs.is_active |
| | 549 | FROM Vendor_Subscription vs |
| | 550 | JOIN Vendor v |
| | 551 | ON v.vendor_id = vs.vendor_id |
| | 552 | JOIN Subscription_Tier st |
| | 553 | ON st.tier_id = vs.tier_id |
| | 554 | ORDER BY v.agency_name, |
| | 555 | vs.is_active DESC, |
| | 556 | vs.start_date DESC; |
| | 557 | }}} |
| | 558 | |
| | 559 | Полето `effective_price` ја користи договорената цена доколку постои. Во спротивно се користи стандардната цена од `Subscription_Tier`. |
| | 560 | |
| | 561 | На овој начин views обезбедуваат готови прикази за најчестите оперативни и аналитички потреби на системот, без истите `JOIN`, `GROUP BY` и агрегатни операции да се повторуваат во секој прашалник. |
| | 562 | |