| 1 | -- =============================================================================
|
|---|
| 2 | -- VIEW 1: Contract details (base view)
|
|---|
| 3 | -- =============================================================================
|
|---|
| 4 | -- Contract details with both parties resolved.
|
|---|
| 5 | CREATE OR REPLACE VIEW vw_contract_details AS
|
|---|
| 6 | SELECT cvc.contract_id,
|
|---|
| 7 | cvc.contract_number,
|
|---|
| 8 | cvc.contract_title,
|
|---|
| 9 | cvc.start_date,
|
|---|
| 10 | cvc.end_date,
|
|---|
| 11 | cvc.total_value,
|
|---|
| 12 | cvc.currency_code,
|
|---|
| 13 | cvc.is_active,
|
|---|
| 14 | c.client_id,
|
|---|
| 15 | c.company_name,
|
|---|
| 16 | v.vendor_id,
|
|---|
| 17 | v.agency_name
|
|---|
| 18 | FROM Client_Vendor_Contract cvc
|
|---|
| 19 | JOIN Client c ON c.client_id = cvc.client_id
|
|---|
| 20 | JOIN Vendor v ON v.vendor_id = cvc.vendor_id;
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 | -- =============================================================================
|
|---|
| 24 | -- VIEW 2: Project details (base view)
|
|---|
| 25 | -- =============================================================================
|
|---|
| 26 | -- Shared project details for the reporting views: the project with its
|
|---|
| 27 | -- status, its contract and both parties.
|
|---|
| 28 | CREATE OR REPLACE VIEW vw_project_details AS
|
|---|
| 29 | SELECT p.project_id,
|
|---|
| 30 | p.project_name,
|
|---|
| 31 | p.status_id,
|
|---|
| 32 | ps.status_name,
|
|---|
| 33 | p.start_date,
|
|---|
| 34 | p.end_date,
|
|---|
| 35 | p.budget,
|
|---|
| 36 | cd.contract_id,
|
|---|
| 37 | cd.contract_number,
|
|---|
| 38 | cd.currency_code,
|
|---|
| 39 | cd.client_id,
|
|---|
| 40 | cd.company_name,
|
|---|
| 41 | cd.vendor_id,
|
|---|
| 42 | cd.agency_name
|
|---|
| 43 | FROM Project p
|
|---|
| 44 | JOIN vw_contract_details cd ON cd.contract_id = p.contract_id
|
|---|
| 45 | JOIN Project_Status ps ON ps.status_id = p.status_id;
|
|---|
| 46 |
|
|---|
| 47 |
|
|---|
| 48 | -- =============================================================================
|
|---|
| 49 | -- VIEW 3: All projects per Vendor
|
|---|
| 50 | -- =============================================================================
|
|---|
| 51 | CREATE OR REPLACE VIEW vw_projects_per_vendor AS
|
|---|
| 52 | SELECT pd.vendor_id,
|
|---|
| 53 | pd.agency_name,
|
|---|
| 54 | pd.project_id,
|
|---|
| 55 | pd.project_name,
|
|---|
| 56 | pd.status_name,
|
|---|
| 57 | pd.start_date,
|
|---|
| 58 | pd.end_date,
|
|---|
| 59 | pd.budget,
|
|---|
| 60 | pd.currency_code
|
|---|
| 61 | FROM vw_project_details pd
|
|---|
| 62 | ORDER BY pd.agency_name, pd.status_name, pd.project_name;
|
|---|
| 63 |
|
|---|
| 64 |
|
|---|
| 65 | -- =============================================================================
|
|---|
| 66 | -- VIEW 4: All projects per Client
|
|---|
| 67 | -- =============================================================================
|
|---|
| 68 | CREATE OR REPLACE VIEW vw_projects_per_client AS
|
|---|
| 69 | SELECT pd.client_id,
|
|---|
| 70 | pd.company_name,
|
|---|
| 71 | pd.project_id,
|
|---|
| 72 | pd.project_name,
|
|---|
| 73 | pd.status_name,
|
|---|
| 74 | pd.start_date,
|
|---|
| 75 | pd.end_date,
|
|---|
| 76 | pd.budget,
|
|---|
| 77 | pd.currency_code
|
|---|
| 78 | FROM vw_project_details pd
|
|---|
| 79 | ORDER BY pd.company_name, pd.status_name, pd.project_name;
|
|---|
| 80 |
|
|---|
| 81 |
|
|---|
| 82 | -- =============================================================================
|
|---|
| 83 | -- VIEW 5: Budget summary per Vendor
|
|---|
| 84 | -- =============================================================================
|
|---|
| 85 | CREATE OR REPLACE VIEW vw_budget_per_vendor AS
|
|---|
| 86 | SELECT pd.vendor_id,
|
|---|
| 87 | pd.agency_name,
|
|---|
| 88 | pd.currency_code,
|
|---|
| 89 | COUNT(pd.project_id) AS project_count,
|
|---|
| 90 | SUM(pd.budget) AS total_budget
|
|---|
| 91 | FROM vw_project_details pd
|
|---|
| 92 | GROUP BY pd.vendor_id, pd.agency_name, pd.currency_code
|
|---|
| 93 | ORDER BY pd.agency_name, pd.currency_code;
|
|---|
| 94 |
|
|---|
| 95 |
|
|---|
| 96 | -- =============================================================================
|
|---|
| 97 | -- VIEW 6: Budget summary per Client
|
|---|
| 98 | -- =============================================================================
|
|---|
| 99 | CREATE OR REPLACE VIEW vw_budget_per_client AS
|
|---|
| 100 | SELECT pd.client_id,
|
|---|
| 101 | pd.company_name,
|
|---|
| 102 | pd.currency_code,
|
|---|
| 103 | COUNT(pd.project_id) AS project_count,
|
|---|
| 104 | SUM(pd.budget) AS total_budget
|
|---|
| 105 | FROM vw_project_details pd
|
|---|
| 106 | GROUP BY pd.client_id, pd.company_name, pd.currency_code
|
|---|
| 107 | ORDER BY pd.company_name, pd.currency_code;
|
|---|
| 108 |
|
|---|
| 109 |
|
|---|
| 110 | -- =============================================================================
|
|---|
| 111 | -- VIEW 7: List of Clients per Industry
|
|---|
| 112 | -- =============================================================================
|
|---|
| 113 | CREATE OR REPLACE VIEW vw_clients_per_industry AS
|
|---|
| 114 | SELECT i.industry_id,
|
|---|
| 115 | i.industry_name,
|
|---|
| 116 | c.client_id,
|
|---|
| 117 | c.company_name,
|
|---|
| 118 | c.contact_email
|
|---|
| 119 | FROM Client c
|
|---|
| 120 | JOIN Industry i ON i.industry_id = c.industry_id
|
|---|
| 121 | ORDER BY i.industry_name, c.company_name;
|
|---|
| 122 |
|
|---|
| 123 |
|
|---|
| 124 | -- =============================================================================
|
|---|
| 125 | -- VIEW 8: Average rating per Vendor (across all rating dimensions)
|
|---|
| 126 | -- =============================================================================
|
|---|
| 127 | -- Aggregates the scores of published reviews. Vendors without a scored
|
|---|
| 128 | -- published review stay in the result with review_count = 0 and
|
|---|
| 129 | -- avg_rating = NULL.
|
|---|
| 130 | -- The scores are summed and counted per review first; the vendor average
|
|---|
| 131 | -- SUM(score_sum) / SUM(score_cnt) is the same score-weighted mean as
|
|---|
| 132 | -- AVG(score_value) over all of the vendor's scores, and each scored review
|
|---|
| 133 | -- is counted once without a COUNT(DISTINCT).
|
|---|
| 134 | CREATE OR REPLACE VIEW vw_avg_rating_per_vendor AS
|
|---|
| 135 | SELECT v.vendor_id,
|
|---|
| 136 | v.agency_name,
|
|---|
| 137 | COUNT(vr.review_id) AS review_count,
|
|---|
| 138 | ROUND(SUM(vr.score_sum) / NULLIF(SUM(vr.score_cnt), 0), 2) AS avg_rating
|
|---|
| 139 | FROM Vendor v
|
|---|
| 140 | LEFT JOIN (SELECT pd.vendor_id,
|
|---|
| 141 | r.review_id,
|
|---|
| 142 | SUM(rs.score_value)::numeric AS score_sum,
|
|---|
| 143 | COUNT(*) AS score_cnt
|
|---|
| 144 | FROM Review r
|
|---|
| 145 | JOIN Review_Score rs ON rs.review_id = r.review_id
|
|---|
| 146 | JOIN vw_project_details pd ON pd.project_id = r.project_id
|
|---|
| 147 | WHERE r.is_published = true
|
|---|
| 148 | GROUP BY pd.vendor_id, r.review_id) vr ON vr.vendor_id = v.vendor_id
|
|---|
| 149 | GROUP BY v.vendor_id, v.agency_name
|
|---|
| 150 | ORDER BY avg_rating DESC NULLS LAST;
|
|---|
| 151 |
|
|---|
| 152 |
|
|---|
| 153 | -- =============================================================================
|
|---|
| 154 | -- VIEW 9: All unresolved Dispute Tickets
|
|---|
| 155 | -- =============================================================================
|
|---|
| 156 | -- The vendor columns identify the agency of the filing user.
|
|---|
| 157 | CREATE OR REPLACE VIEW vw_unresolved_dispute_tickets AS
|
|---|
| 158 | SELECT dt.ticket_id,
|
|---|
| 159 | dt.filed_at,
|
|---|
| 160 | dt.reason,
|
|---|
| 161 | r.review_id,
|
|---|
| 162 | p.project_id,
|
|---|
| 163 | p.project_name,
|
|---|
| 164 | dt.vendor_user_id AS filed_by_vendor_user_id,
|
|---|
| 165 | vusr.first_name || ' ' || vusr.last_name AS filed_by_vendor_user,
|
|---|
| 166 | dt.assigned_management_user_id,
|
|---|
| 167 | musr.first_name || ' ' || musr.last_name AS assigned_to_management_user,
|
|---|
| 168 | dt.created_at,
|
|---|
| 169 | dt.updated_at,
|
|---|
| 170 | ven.vendor_id,
|
|---|
| 171 | ven.agency_name
|
|---|
| 172 | FROM Dispute_Ticket dt
|
|---|
| 173 | JOIN Review r ON r.review_id = dt.review_id
|
|---|
| 174 | JOIN Project p ON p.project_id = r.project_id
|
|---|
| 175 | JOIN Vendor_User vu ON vu.user_id = dt.vendor_user_id
|
|---|
| 176 | JOIN Vendor ven ON ven.vendor_id = vu.vendor_id
|
|---|
| 177 | JOIN "User" vusr ON vusr.user_id = vu.user_id
|
|---|
| 178 | LEFT JOIN "User" musr ON musr.user_id = dt.assigned_management_user_id
|
|---|
| 179 | WHERE dt.is_resolved = false
|
|---|
| 180 | ORDER BY dt.filed_at;
|
|---|
| 181 |
|
|---|
| 182 |
|
|---|
| 183 | -- =============================================================================
|
|---|
| 184 | -- VIEW 10: Project count per Status per Vendor
|
|---|
| 185 | -- =============================================================================
|
|---|
| 186 | CREATE OR REPLACE VIEW vw_project_count_by_status_per_vendor AS
|
|---|
| 187 | SELECT pd.vendor_id,
|
|---|
| 188 | pd.agency_name,
|
|---|
| 189 | pd.status_id,
|
|---|
| 190 | pd.status_name,
|
|---|
| 191 | COUNT(pd.project_id) AS project_count
|
|---|
| 192 | FROM vw_project_details pd
|
|---|
| 193 | GROUP BY pd.vendor_id, pd.agency_name, pd.status_id, pd.status_name
|
|---|
| 194 | ORDER BY pd.agency_name, pd.status_name;
|
|---|
| 195 |
|
|---|
| 196 |
|
|---|
| 197 | -- =============================================================================
|
|---|
| 198 | -- VIEW 11: Project count per Status per Client
|
|---|
| 199 | -- =============================================================================
|
|---|
| 200 | CREATE OR REPLACE VIEW vw_project_count_by_status_per_client AS
|
|---|
| 201 | SELECT pd.client_id,
|
|---|
| 202 | pd.company_name,
|
|---|
| 203 | pd.status_id,
|
|---|
| 204 | pd.status_name,
|
|---|
| 205 | COUNT(pd.project_id) AS project_count
|
|---|
| 206 | FROM vw_project_details pd
|
|---|
| 207 | GROUP BY pd.client_id, pd.company_name, pd.status_id, pd.status_name
|
|---|
| 208 | ORDER BY pd.company_name, pd.status_name;
|
|---|
| 209 |
|
|---|
| 210 |
|
|---|
| 211 | -- =============================================================================
|
|---|
| 212 | -- VIEW 12: Contracts per Vendor
|
|---|
| 213 | -- =============================================================================
|
|---|
| 214 | CREATE OR REPLACE VIEW vw_contracts_per_vendor AS
|
|---|
| 215 | SELECT cd.vendor_id,
|
|---|
| 216 | cd.agency_name,
|
|---|
| 217 | cd.contract_id,
|
|---|
| 218 | cd.contract_number,
|
|---|
| 219 | cd.contract_title,
|
|---|
| 220 | cd.client_id,
|
|---|
| 221 | cd.company_name AS client_name,
|
|---|
| 222 | cd.start_date,
|
|---|
| 223 | cd.end_date,
|
|---|
| 224 | cd.total_value,
|
|---|
| 225 | cd.currency_code,
|
|---|
| 226 | cd.is_active
|
|---|
| 227 | FROM vw_contract_details cd
|
|---|
| 228 | ORDER BY cd.agency_name, cd.is_active DESC, cd.start_date DESC;
|
|---|
| 229 |
|
|---|
| 230 |
|
|---|
| 231 | -- =============================================================================
|
|---|
| 232 | -- VIEW 13: Contracts per Client
|
|---|
| 233 | -- =============================================================================
|
|---|
| 234 | CREATE OR REPLACE VIEW vw_contracts_per_client AS
|
|---|
| 235 | SELECT cd.client_id,
|
|---|
| 236 | cd.company_name,
|
|---|
| 237 | cd.contract_id,
|
|---|
| 238 | cd.contract_number,
|
|---|
| 239 | cd.contract_title,
|
|---|
| 240 | cd.vendor_id,
|
|---|
| 241 | cd.agency_name AS vendor_name,
|
|---|
| 242 | cd.start_date,
|
|---|
| 243 | cd.end_date,
|
|---|
| 244 | cd.total_value,
|
|---|
| 245 | cd.currency_code,
|
|---|
| 246 | cd.is_active
|
|---|
| 247 | FROM vw_contract_details cd
|
|---|
| 248 | ORDER BY cd.company_name, cd.is_active DESC, cd.start_date DESC;
|
|---|
| 249 |
|
|---|
| 250 |
|
|---|
| 251 | -- =============================================================================
|
|---|
| 252 | -- VIEW 14: Vendor subscription status
|
|---|
| 253 | -- =============================================================================
|
|---|
| 254 | CREATE OR REPLACE VIEW vw_vendor_subscriptions AS
|
|---|
| 255 | SELECT v.vendor_id,
|
|---|
| 256 | v.agency_name,
|
|---|
| 257 | st.tier_id,
|
|---|
| 258 | st.tier_name,
|
|---|
| 259 | COALESCE(vs.negotiated_price, st.list_price, 0) AS effective_price,
|
|---|
| 260 | vs.start_date,
|
|---|
| 261 | vs.end_date,
|
|---|
| 262 | vs.is_active
|
|---|
| 263 | FROM Vendor_Subscription vs
|
|---|
| 264 | JOIN Vendor v ON v.vendor_id = vs.vendor_id
|
|---|
| 265 | JOIN Subscription_Tier st ON st.tier_id = vs.tier_id
|
|---|
| 266 | ORDER BY v.agency_name, vs.is_active DESC, vs.start_date DESC;
|
|---|
| 267 |
|
|---|
| 268 |
|
|---|
| 269 | -- =============================================================================
|
|---|
| 270 | -- VIEW 15: Rating per Vendor broken down by rating dimension
|
|---|
| 271 | -- =============================================================================
|
|---|
| 272 | -- Per-dimension scores from published reviews.
|
|---|
| 273 | CREATE OR REPLACE VIEW vw_vendor_rating_by_dimension AS
|
|---|
| 274 | SELECT pd.vendor_id,
|
|---|
| 275 | pd.agency_name,
|
|---|
| 276 | rd.dimension_id,
|
|---|
| 277 | rd.dimension_name,
|
|---|
| 278 | COUNT(*) AS score_count,
|
|---|
| 279 | ROUND(AVG(rs.score_value), 2) AS avg_score,
|
|---|
| 280 | MIN(rs.score_value) AS min_score,
|
|---|
| 281 | MAX(rs.score_value) AS max_score
|
|---|
| 282 | FROM Review_Score rs
|
|---|
| 283 | JOIN Rating_Dimension rd ON rd.dimension_id = rs.dimension_id
|
|---|
| 284 | JOIN Review r ON r.review_id = rs.review_id
|
|---|
| 285 | JOIN vw_project_details pd ON pd.project_id = r.project_id
|
|---|
| 286 | WHERE r.is_published = true
|
|---|
| 287 | GROUP BY pd.vendor_id, pd.agency_name, rd.dimension_id, rd.dimension_name;
|
|---|
| 288 |
|
|---|
| 289 |
|
|---|
| 290 | -- =============================================================================
|
|---|
| 291 | -- VIEW 16: Budget changes per Project (the budget audit trail)
|
|---|
| 292 | -- =============================================================================
|
|---|
| 293 | -- One row per recorded budget change; delta and pct_change are derived here.
|
|---|
| 294 | CREATE OR REPLACE VIEW vw_project_budget_changes AS
|
|---|
| 295 | SELECT pba.audit_id,
|
|---|
| 296 | pd.project_id,
|
|---|
| 297 | pd.project_name,
|
|---|
| 298 | pd.vendor_id,
|
|---|
| 299 | pd.client_id,
|
|---|
| 300 | pd.currency_code,
|
|---|
| 301 | pba.old_budget,
|
|---|
| 302 | pba.new_budget,
|
|---|
| 303 | pba.new_budget - pba.old_budget AS delta,
|
|---|
| 304 | ROUND(100.0 * (pba.new_budget - pba.old_budget) / NULLIF(pba.old_budget, 0), 1) AS pct_change,
|
|---|
| 305 | pba.created_at AS changed_at
|
|---|
| 306 | FROM Project_Budget_Audit pba
|
|---|
| 307 | JOIN vw_project_details pd ON pd.project_id = pba.project_id;
|
|---|