| 1 | CREATE OR REPLACE FUNCTION public.find_nearest_network_sites(
|
|---|
| 2 | p_latitude double precision,
|
|---|
| 3 | p_longitude double precision,
|
|---|
| 4 | p_max_distance_m double precision DEFAULT 10000,
|
|---|
| 5 | p_limit integer DEFAULT 5
|
|---|
| 6 | )
|
|---|
| 7 | RETURNS TABLE
|
|---|
| 8 | (
|
|---|
| 9 | site_id bigint,
|
|---|
| 10 | site_code text,
|
|---|
| 11 | site_name text,
|
|---|
| 12 | region text,
|
|---|
| 13 | distance_m numeric,
|
|---|
| 14 | active_technologies text
|
|---|
| 15 | )
|
|---|
| 16 | LANGUAGE plpgsql
|
|---|
| 17 | STABLE
|
|---|
| 18 | AS $$
|
|---|
| 19 | BEGIN
|
|---|
| 20 | IF p_latitude < -90 OR p_latitude > 90 THEN
|
|---|
| 21 | RAISE EXCEPTION 'Latitude must be between -90 and 90';
|
|---|
| 22 | END IF;
|
|---|
| 23 |
|
|---|
| 24 | IF p_longitude < -180 OR p_longitude > 180 THEN
|
|---|
| 25 | RAISE EXCEPTION 'Longitude must be between -180 and 180';
|
|---|
| 26 | END IF;
|
|---|
| 27 |
|
|---|
| 28 | IF p_max_distance_m <= 0 THEN
|
|---|
| 29 | RAISE EXCEPTION 'Maximum distance must be positive';
|
|---|
| 30 | END IF;
|
|---|
| 31 |
|
|---|
| 32 | IF p_limit < 1 OR p_limit > 100 THEN
|
|---|
| 33 | RAISE EXCEPTION 'Limit must be between 1 and 100';
|
|---|
| 34 | END IF;
|
|---|
| 35 |
|
|---|
| 36 | RETURN QUERY
|
|---|
| 37 | WITH search_point AS
|
|---|
| 38 | (
|
|---|
| 39 | SELECT ST_SetSRID(ST_MakePoint(p_longitude, p_latitude), 4326) AS location
|
|---|
| 40 | )
|
|---|
| 41 | SELECT
|
|---|
| 42 | ns.site_id,
|
|---|
| 43 | ns.site_code,
|
|---|
| 44 | ns.site_name,
|
|---|
| 45 | ns.region,
|
|---|
| 46 | round(
|
|---|
| 47 | ST_Distance(ns.location::geography, sp.location::geography)::numeric,
|
|---|
| 48 | 1
|
|---|
| 49 | ) AS distance_m,
|
|---|
| 50 | coalesce(technologies.names, 'No active sectors') AS active_technologies
|
|---|
| 51 | FROM public.network_sites ns
|
|---|
| 52 | CROSS JOIN search_point sp
|
|---|
| 53 | LEFT JOIN LATERAL
|
|---|
| 54 | (
|
|---|
| 55 | SELECT string_agg(
|
|---|
| 56 | DISTINCT concat(nt.generation, ' ', nt.technology_name),
|
|---|
| 57 | ', '
|
|---|
| 58 | ORDER BY concat(nt.generation, ' ', nt.technology_name)
|
|---|
| 59 | ) AS names
|
|---|
| 60 | FROM public.cell_towers ct
|
|---|
| 61 | JOIN public.tower_sectors ts ON ts.tower_id = ct.tower_id
|
|---|
| 62 | JOIN public.network_technologies nt
|
|---|
| 63 | ON nt.technology_id = ts.technology_id
|
|---|
| 64 | WHERE ct.site_id = ns.site_id
|
|---|
| 65 | AND ct.status = 'active'
|
|---|
| 66 | AND ts.status = 'active'
|
|---|
| 67 | AND nt.status = 'active'
|
|---|
| 68 | ) technologies ON true
|
|---|
| 69 | WHERE ns.status = 'active'
|
|---|
| 70 | AND ns.location IS NOT NULL
|
|---|
| 71 | AND ST_DWithin(
|
|---|
| 72 | ns.location::geography,
|
|---|
| 73 | sp.location::geography,
|
|---|
| 74 | p_max_distance_m
|
|---|
| 75 | )
|
|---|
| 76 | ORDER BY ns.location::geography <-> sp.location::geography
|
|---|
| 77 | LIMIT p_limit;
|
|---|
| 78 | END;
|
|---|
| 79 | $$;
|
|---|