Domify
Напредни извештаи од базата (SQL и складирани процедури)
1. Извештај за процент на изнајмени недвижности во однос на објавени огласи за секоја година.
WITH total_listings AS ( SELECT EXTRACT(YEAR FROM available_from) AS year, COUNT(*) AS listing_count FROM Listing GROUP BY year ), converted_listings AS ( SELECT EXTRACT(YEAR FROM l.start_date) AS year, COUNT(DISTINCT li.id) AS converted FROM Lease l JOIN Listing li ON l.listing_id = li.id GROUP BY year ) SELECT tl.year, tl.listing_count, COALESCE(cl.converted, 0) AS converted, ROUND(100.0 * COALESCE(cl.converted, 0) / tl.listing_count, 2) AS conversion_rate FROM total_listings tl LEFT JOIN converted_listings cl ON tl.year = cl.year ORDER BY tl.year;
2. Извештај за раст на приходи (извршени успешни плаќања за изнајмувања) за претходна и тековна година за секој град изразена во проценти.
WITH yearly_income AS ( SELECT a.city, EXTRACT(YEAR FROM p.payment_date) AS year, SUM(p.amount) AS total_revenue FROM Payment p JOIN Lease l ON l.id = p.lease_id JOIN Listing li ON li.id = l.listing_id JOIN Unit u ON li.unit_id = u.id JOIN Property pr ON u.property_id = pr.id JOIN Address a ON pr.address_id = a.id WHERE p.status = 'завршено' GROUP BY a.city, year ), diffs AS ( SELECT curr.city, curr.total_revenue AS this_year, prev.total_revenue AS last_year, ROUND(((curr.total_revenue - prev.total_revenue) / NULLIF(prev.total_revenue, 0)) * 100, 2) AS growth_percent FROM yearly_income curr JOIN yearly_income prev ON prev.city = curr.city AND curr.year = prev.year + 1 WHERE curr.year = EXTRACT(YEAR FROM CURRENT_DATE) ) SELECT * FROM diffs ORDER BY growth_percent DESC;
3. Детален месечен извештај за приходите, наплатата, останатиот долг, ненаплатените и активните изнајмувања и нерешените сервисни барања на изнајмувачите
WITH month_period AS ( SELECT DATE_TRUNC('month', CURRENT_DATE) - INTERVAL '1 month' AS month_start, (DATE_TRUNC('month', CURRENT_DATE) - INTERVAL '1 month') + INTERVAL '1 month - 1 day' AS month_end ), landlords AS ( SELECT lp.id AS landlord_id, u.first_name || ' ' || u.last_name AS landlord_name FROM domify.LandlordProfile lp JOIN domify.UserD u ON lp.id = u.id ), total_due_cte AS ( SELECT l.landlord_id, COALESCE(SUM(l.rent_amount), 0) AS total_due FROM domify.Lease l CROSS JOIN month_period mp WHERE l.start_date <= mp.month_end AND l.end_date >= mp.month_start GROUP BY l.landlord_id ), total_paid_cte AS ( SELECT l.landlord_id, COALESCE(SUM(p.amount), 0) AS total_paid FROM domify.Payment p JOIN domify.Lease l ON p.lease_id = l.id CROSS JOIN month_period mp WHERE p.payment_date BETWEEN mp.month_start AND mp.month_end AND p.status IN ('completed','paid') GROUP BY l.landlord_id ), late_count_cte AS ( SELECT l.landlord_id, COUNT(*) AS late_count FROM domify.Lease l CROSS JOIN month_period mp WHERE l.start_date <= mp.month_end AND l.end_date >= mp.month_start AND NOT EXISTS ( SELECT 1 FROM domify.Payment p WHERE p.lease_id = l.id AND p.payment_date BETWEEN mp.month_start AND mp.month_end AND p.status IN ('completed','paid') ) GROUP BY l.landlord_id ), active_leases_cte AS ( SELECT l.landlord_id, COUNT(*) AS active_leases FROM domify.Lease l WHERE l.start_date <= CURRENT_DATE AND l.end_date >= CURRENT_DATE GROUP BY l.landlord_id ), pending_services_cte AS ( SELECT l.landlord_id, COUNT(*) AS pending_services FROM domify.ServiceRequest sr JOIN domify.Lease l ON sr.lease_id = l.id WHERE sr.status IN ('pending','in_progress') GROUP BY l.landlord_id ) SELECT ld.landlord_id, ld.landlord_name, td.total_due, tp.total_paid, (td.total_due - tp.total_paid) AS remaining_debt, lc.late_count, al.active_leases, ps.pending_services FROM landlords ld CROSS JOIN month_period mp LEFT JOIN total_due_cte td ON ld.landlord_id = td.landlord_id LEFT JOIN total_paid_cte tp ON ld.landlord_id = tp.landlord_id LEFT JOIN late_count_cte lc ON ld.landlord_id = lc.landlord_id LEFT JOIN active_leases_cte al ON ld.landlord_id = al.landlord_id LEFT JOIN pending_services_cte ps ON ld.landlord_id = ps.landlord_id ORDER BY ld.landlord_name;
4. Детален извештај за историјата на плаќања, задоцнети и тековни обврски, просечна кирија и оценка на платежната дисциплина на изнајмувачите
WITH TenantPaymentStats AS ( SELECT t.id as tenant_id, CONCAT(u.first_name, ' ', u.last_name) as tenant_name, u.rating as tenant_rating, COUNT(DISTINCT le.id) as total_leases, COUNT(DISTINCT pay.id) as total_payments, SUM(CASE WHEN pay.status = 'завршено' THEN pay.amount ELSE 0 END) as total_paid, SUM(CASE WHEN pay.status = 'доцнење' THEN pay.amount ELSE 0 END) as late_payments_amount, COUNT(CASE WHEN pay.status = 'доцнење' THEN 1 END) as late_payment_count, COUNT(CASE WHEN pay.status = 'во тек' THEN 1 END) as pending_payment_count, AVG(le.rent_amount) as avg_rent_amount, MIN(le.start_date) as first_lease_date, MAX(le.end_date) as latest_lease_end FROM TenantProfile t JOIN UserD u ON t.id = u.id LEFT JOIN Lease le ON t.id = le.tenant_id LEFT JOIN Payment pay ON le.id = pay.lease_id GROUP BY t.id, u.first_name, u.last_name, u.rating ) SELECT tenant_id, tenant_name, tenant_rating, total_leases, total_payments, total_paid, late_payments_amount, late_payment_count, pending_payment_count, ROUND((late_payment_count * 100.0 / NULLIF(total_payments, 0)), 2) as late_payment_percentage, avg_rent_amount, first_lease_date, latest_lease_end, CASE WHEN late_payment_count = 0 THEN 'Одличен' WHEN late_payment_count <= 2 THEN 'Добар' WHEN late_payment_count <= 5 THEN 'Среден' ELSE 'Ризичен' END as payment_reliability_score FROM TenantPaymentStats WHERE total_leases > 0 ORDER BY late_payment_percentage ASC, total_paid DESC;
5. Детален извештај за сервисни барања, стапка на завршување и просечно време на решавање по општина и град
SET search_path TO domify, public; WITH MaintenanceAnalysis AS ( SELECT a.municipality, a.city, sc.name as service_category, COUNT(sr.id) as total_requests, COUNT(CASE WHEN sr.status = 'завршено' THEN 1 END) as completed_requests, COUNT(CASE WHEN sr.status = 'во тек' THEN 1 END) as in_progress_requests, COUNT(CASE WHEN sr.status = 'во очекување' THEN 1 END) as pending_requests, AVG(CASE WHEN sr.status = 'завршено' AND ml.maintenance_date IS NOT NULL THEN (ml.maintenance_date::date - sr.request_date::date) END) as avg_resolution_days FROM ServiceRequest sr JOIN ServiceCategory sc ON sr.service_category_id = sc.id JOIN Lease le ON sr.lease_id = le.id JOIN Listing l ON le.listing_id = l.id JOIN Unit u ON l.unit_id = u.id JOIN Property p ON u.property_id = p.id JOIN Address a ON p.address_id = a.id LEFT JOIN MaintenanceLog ml ON sr.id = ml.service_request_id GROUP BY a.municipality, a.city, sc.name ) SELECT municipality, city, service_category, total_requests, completed_requests, in_progress_requests, pending_requests, ROUND((completed_requests * 100.0 / NULLIF(total_requests, 0)), 2) as completion_rate_percent, ROUND(avg_resolution_days, 1) as avg_resolution_days, CASE WHEN avg_resolution_days <= 2 THEN 'Брзо' WHEN avg_resolution_days <= 5 THEN 'Средно' WHEN avg_resolution_days <= 10 THEN 'Бавно' ELSE 'Многу бавно' END as response_time_rating FROM MaintenanceAnalysis ORDER BY municipality, total_requests DESC;
6.Анализа на пазарни трендови и изнајмувачка понуда по општина, град и тип на недвижност
SET search_path TO domify, public; WITH MarketTrends AS ( SELECT a.municipality, a.city, pt.name as property_type, COUNT(DISTINCT l.id) as total_listings, COUNT(DISTINCT CASE WHEN l.status = 'available' THEN l.id END) as available_listings, AVG(u.rent_amount) as avg_rent_asking, AVG(le.rent_amount) as avg_rent_actual, AVG(u.area_sq_m) as avg_unit_size, AVG(u.rent_amount / u.area_sq_m) as avg_rent_per_sq_m, MIN(u.rent_amount) as min_rent, MAX(u.rent_amount) as max_rent, COUNT(DISTINCT in_list.tenant_profile_id) as total_interested_tenants FROM Address a JOIN Property p ON a.id = p.address_id JOIN PropertyType pt ON p.property_type_id = pt.id JOIN Unit u ON p.id = u.property_id JOIN Listing l ON u.id = l.unit_id LEFT JOIN Lease le ON l.id = le.listing_id LEFT JOIN Interested in_list ON l.id = in_list.listing_id GROUP BY a.municipality, a.city, pt.name ) SELECT municipality, city, property_type, total_listings, available_listings, ROUND((available_listings * 100.0 / NULLIF(total_listings, 0)), 2) as availability_rate, ROUND(avg_rent_asking, 2) as avg_rent_asking, ROUND(avg_rent_actual, 2) as avg_rent_actual, ROUND((avg_rent_actual - avg_rent_asking), 2) as rent_variance, ROUND(avg_unit_size, 1) as avg_unit_size_sq_m, ROUND(avg_rent_per_sq_m, 2) as avg_rent_per_sq_m, min_rent, max_rent, total_interested_tenants, ROUND(total_interested_tenants / NULLIF(available_listings, 0), 2) as interest_ratio, CASE WHEN ROUND((available_listings * 100.0 / NULLIF(total_listings, 0)), 2) > 75 THEN 'Висока понуда' WHEN ROUND((available_listings * 100.0 / NULLIF(total_listings, 0)), 2) > 50 THEN 'Умерена понуда' WHEN ROUND((available_listings * 100.0 / NULLIF(total_listings, 0)), 2) > 25 THEN 'Ограничена понуда' ELSE 'Ниска Понуда' END as market_availability_status FROM MarketTrends WHERE total_listings > 0 ORDER BY municipality, avg_rent_per_sq_m DESC;
Историја
Last modified
29 hours ago
Last modified on 08/16/25 00:22:42
Note:
See TracWiki
for help on using the wiki.