50+ battle-tested SQL queries for real estate valuation, finance & portfolio analysts
100% free • copy, paste, run • no signup • no email
SELECT
property_name,
COUNT(DISTINCT unit) AS total_units,
SUM(monthly_rent) AS total_mrr,
SUM(monthly_rent*12)/NULLIF(SUM(rsf),0) AS avg_annual_per_sf,
AVG(DATEDIFF(month, GETDATE(), lease_expiry)) / 12.0 AS walt_years
FROM rent_roll
WHERE lease_status = 'Occupied'
GROUP BY property_name
ORDER BY total_mrr DESC;
SELECT
YEAR(lease_expiry) AS exp_year,
MONTH(lease_expiry) AS exp_month,
COUNT(*) AS leases_expiring,
SUM(monthly_rent*12) AS annual_rent_at_risk,
SUM(rsf) AS sf_expiring
FROM rent_roll
WHERE lease_expiry BETWEEN GETDATE() AND DATEADD(month,24,GETDATE())
GROUP BY YEAR(lease_expiry), MONTH(lease_expiry)
ORDER BY exp_year, exp_month;
WITH cleaned AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY property_id, unit_number ORDER BY export_date DESC) AS rn
FROM argus_export
WHERE unit_status NOT IN ('Model','Future','Hold')
)
SELECT * EXCEPT(rn) FROM cleaned WHERE rn = 1;
SELECT
FORMAT_DATE('%Y-%m', month_date) AS period,
ROUND(100.0 * SUM(vacant_sf) / NULLIF(SUM(total_sf),0), 2) AS physical_vacancy_pct,
ROUND(100.0 * (SUM(vacant_sf) - SUM(under_construction_sf)) / NULLIF(SUM(total_sf - under_construction_sf),0), 2) AS economic_vacancy_pct
FROM monthly_snapshot
WHERE month_date >= DATE_ADD(CURRENT_DATE(), INTERVAL -36 MONTH)
GROUP BY period
ORDER BY period;
SELECT
property_id,
SUM(CASE WHEN month_date >= DATE_ADD(CURRENT_DATE(), INTERVAL -12 MONTH) THEN noi ELSE 0 END) AS t12_noi,
SUM(CASE WHEN month_date >= DATE_ADD(CURRENT_DATE(), INTERVAL -3 MONTH) THEN noi * 4 ELSE 0 END) AS t3_annualized_noi
FROM financials_monthly
GROUP BY property_id;
SELECT
property_type,
COUNT(*) AS count,
ROUND(AVG(cap_rate),3) AS avg_cap_rate,
PERCENTILE_CONT(cap_rate, 0.25) OVER (PARTITION BY property_type) AS p25,
PERCENTILE_CONT(cap_rate, 0.50) OVER (PARTITION BY property_type) AS median,
PERCENTILE_CONT(cap_rate, 0.75) OVER (PARTITION BY property_type) AS p75
FROM portfolio_valuations
WHERE valuation_date = (SELECT MAX(valuation_date) FROM portfolio_valuations)
GROUP BY property_type
ORDER BY avg_cap_rate;
SELECT
p.property_name,
l.lender,
ROUND(f.t12_noi / NULLIF(l.annual_debt_service,0), 2) AS dscr_t12,
CASE WHEN ROUND(f.t12_noi / NULLIF(l.annual_debt_service,0), 2) < 1.25 THEN 'Watch' ELSE 'Pass' END AS covenant_status
FROM loans l
JOIN properties p ON p.property_id = l.property_id
JOIN financials f ON f.property_id = p.property_id;
SELECT
tenant_name,
SUM(annual_rent) AS annual_rent,
ROUND(100.0 * SUM(annual_rent) / TOTAL_SUM.total_rent, 2) AS pct_of_portfolio
FROM rent_roll r
CROSS JOIN (SELECT SUM(annual_rent) AS total_rent FROM rent_roll WHERE lease_status = 'Occupied') TOTAL_SUM
WHERE lease_status = 'Occupied'
GROUP BY tenant_name, TOTAL_SUM.total_rent
ORDER BY annual_rent DESC
LIMIT 20;
SELECT
property_name,
exit_year,
exit_cap_rate,
ROUND((POW(exit_value / purchase_price, 1.0/hold_years) - 1) * 100, 2) AS irr_pct
FROM (
SELECT
property_name,
purchase_price,
projected_noi * 12 / exit_cap_rate AS exit_value,
hold_years,
exit_cap_rate,
(2025 + hold_years) AS exit_year
FROM sensitivity_inputs
)
ORDER BY property_name, exit_year, exit_cap_rate;
10. Recovery Rate by Expense Type
11. Same-Store NOI Growth YoY
12. Average Remaining Lease Term (WALT)
13. Credit Loss Provision Forecast
14. Market Rent vs In-Place Rent Gap
…and 36 more senior-level queries
SELECT expense_type,
ROUND(100.0 * SUM(recovered_amount) / NULLIF(SUM(gross_expense),0), 2) AS recovery_rate_pct
FROM operating_expenses
WHERE fiscal_year = 2024
GROUP BY expense_type
ORDER BY recovery_rate_pct DESC;
WITH ss AS (
SELECT property_id, YEAR(month_date) AS yr, SUM(noi) AS noi
FROM financials_monthly
WHERE property_id IN (SELECT property_id FROM acquisitions WHERE acquisition_date <= '2022-12-31')
GROUP BY property_id, yr
)
SELECT curr.yr,
ROUND(100.0 * (SUM(curr.noi) - SUM(prev.noi)) / SUM(prev.noi), 2) AS ss_noi_growth_pct
FROM ss curr
LEFT JOIN ss prev ON prev.property_id = curr.property_id AND prev.yr = curr.yr - 1
GROUP BY curr.yr HAVING prev.yr IS NOT NULL
ORDER BY curr.yr;
SELECT ROUND(SUM(months_remaining * annual_rent) / NULLIF(SUM(annual_rent),0) / 12.0, 1) AS walt_years
FROM rent_roll
WHERE lease_status = 'Occupied';
SELECT
SUM(CASE WHEN credit_rating IN ('BB','B','CCC') THEN annual_rent * 0.15
WHEN credit_rating = 'NR' THEN annual_rent * 0.25
ELSE 0 END) / 12 AS monthly_credit_loss_forecast
FROM rent_roll
WHERE lease_expiry > CURRENT_DATE;
SELECT
property_name,
ROUND(100.0 * (market_rent_per_sf - in_place_rent_per_sf) / market_rent_per_sf, 1) AS mark_to_market_pct
FROM rent_roll
WHERE market_rent_per_sf IS NOT NULL;