-- pSEO article data: per-city padel court pricing. -- One row per city — consumed by the city-pricing.md.jinja template. -- Joins venue_pricing_benchmarks (real Playtomic data) with city_market_profile -- (population, venue count, country metadata). -- -- Stricter filter than pseo_city_costs_de: requires >= 2 venues with real -- pricing data so pricing articles are always data-backed. MODEL ( name serving.pseo_city_pricing, kind FULL, cron '@daily', grain city_key ); SELECT -- Composite natural key: country_slug + city_slug ensures uniqueness across countries c.country_slug || '-' || c.city_slug AS city_key, -- City identity (from city_market_profile, which has the canonical city_slug) c.city_slug, c.city_name, c.country_code, c.country_name_en, c.country_slug, -- Market context c.population, c.padel_venue_count, c.venues_per_100k, c.market_score, -- Pricing benchmarks (from Playtomic availability data) vpb.median_hourly_rate, vpb.median_peak_rate, vpb.median_offpeak_rate, vpb.hourly_rate_p25, vpb.hourly_rate_p75, vpb.median_occupancy_rate, vpb.venue_count, vpb.price_currency, CURRENT_DATE AS refreshed_date FROM serving.venue_pricing_benchmarks vpb -- Join city_market_profile to get the canonical city_slug and country metadata INNER JOIN serving.city_market_profile c ON vpb.country_code = c.country_code AND vpb.city_slug = c.city_slug -- Only cities with enough venues for meaningful pricing statistics WHERE vpb.venue_count >= 2