MIF_E31221222/sigap-website/supabase/migrations/20250505150200_remote_schem...

205 lines
5.8 KiB
PL/PgSQL

grant delete on table "storage"."s3_multipart_uploads" to "postgres";
grant insert on table "storage"."s3_multipart_uploads" to "postgres";
grant references on table "storage"."s3_multipart_uploads" to "postgres";
grant select on table "storage"."s3_multipart_uploads" to "postgres";
grant trigger on table "storage"."s3_multipart_uploads" to "postgres";
grant truncate on table "storage"."s3_multipart_uploads" to "postgres";
grant update on table "storage"."s3_multipart_uploads" to "postgres";
grant delete on table "storage"."s3_multipart_uploads_parts" to "postgres";
grant insert on table "storage"."s3_multipart_uploads_parts" to "postgres";
grant references on table "storage"."s3_multipart_uploads_parts" to "postgres";
grant select on table "storage"."s3_multipart_uploads_parts" to "postgres";
grant trigger on table "storage"."s3_multipart_uploads_parts" to "postgres";
grant truncate on table "storage"."s3_multipart_uploads_parts" to "postgres";
grant update on table "storage"."s3_multipart_uploads_parts" to "postgres";
-- drop type "gis"."geometry_dump";
-- drop type "gis"."valid_detail";
set check_function_bodies = off;
CREATE OR REPLACE FUNCTION gis.calculate_unit_incident_distances(p_unit_id character varying, p_district_id character varying DEFAULT NULL::character varying)
RETURNS TABLE(unit_code character varying, unit_name character varying, unit_lat double precision, unit_lng double precision, incident_id character varying, incident_description text, incident_lat double precision, incident_lng double precision, category_name character varying, district_name character varying, distance_meters double precision)
LANGUAGE plpgsql
SECURITY DEFINER
AS $function$
BEGIN
RETURN QUERY
WITH unit_locations AS (
SELECT
u.code_unit,
u.name,
u.latitude,
u.longitude,
u.district_id,
ST_SetSRID(ST_MakePoint(u.longitude, u.latitude), 4326)::geography AS location
FROM
units u
WHERE
(p_unit_id IS NULL OR u.code_unit = p_unit_id)
AND (p_district_id IS NULL OR u.district_id = p_district_id)
AND u.latitude IS NOT NULL
AND u.longitude IS NOT NULL
),
incident_locations AS (
SELECT
ci.id,
ci.description,
ci.crime_id,
ci.crime_category_id,
l.latitude,
l.longitude,
ST_SetSRID(ST_MakePoint(l.longitude, l.latitude), 4326)::geography AS location
FROM
crime_incidents ci
JOIN
locations l ON ci.location_id = l.id
WHERE
l.latitude IS NOT NULL
AND l.longitude IS NOT NULL
)
SELECT
ul.code_unit as unit_code,
ul.name as unit_name,
ul.latitude as unit_lat,
ul.longitude as unit_lng,
il.id as incident_id,
il.description as incident_description,
il.latitude as incident_lat,
il.longitude as incident_lng,
cc.name as category_name,
d.name as district_name,
ST_Distance(ul.location, il.location) as distance_meters
FROM
unit_locations ul
JOIN
districts d ON ul.district_id = d.id
JOIN
crimes c ON c.district_id = d.id
JOIN
incident_locations il ON il.crime_id = c.id
JOIN
crime_categories cc ON il.crime_category_id = cc.id
ORDER BY
ul.code_unit,
ul.location <-> il.location; -- Use KNN operator for efficient ordering
END;
$function$
;
CREATE OR REPLACE FUNCTION gis.find_nearest_unit_to_incident(p_incident_id integer)
RETURNS TABLE(unit_code text, unit_name text, distance_meters double precision)
LANGUAGE plpgsql
SECURITY DEFINER
AS $function$
BEGIN
RETURN QUERY
WITH incident_location AS (
SELECT
ci.id,
ST_SetSRID(ST_MakePoint(
(ci.locations->>'longitude')::float,
(ci.locations->>'latitude')::float
), 4326)::geography AS location
FROM
crime_incidents ci
WHERE
ci.id = p_incident_id
AND (ci.locations->>'latitude') IS NOT NULL
AND (ci.locations->>'longitude') IS NOT NULL
),
unit_locations AS (
SELECT
u.code_unit,
u.name,
ST_SetSRID(ST_MakePoint(u.longitude, u.latitude), 4326)::geography AS location
FROM
units u
WHERE
u.latitude IS NOT NULL
AND u.longitude IS NOT NULL
)
SELECT
ul.code_unit as unit_code,
ul.name as unit_name,
ST_Distance(ul.location, il.location) as distance_meters
FROM
unit_locations ul
CROSS JOIN
incident_location il
ORDER BY
ul.location <-> il.location
LIMIT 1;
END;
$function$
;
CREATE OR REPLACE FUNCTION gis.find_units_within_distance(p_incident_id integer, p_max_distance_meters double precision DEFAULT 5000)
RETURNS TABLE(unit_code text, unit_name text, distance_meters double precision)
LANGUAGE plpgsql
SECURITY DEFINER
AS $function$
BEGIN
RETURN QUERY
WITH incident_location AS (
SELECT
ci.id,
ST_SetSRID(ST_MakePoint(
(ci.locations->>'longitude')::float,
(ci.locations->>'latitude')::float
), 4326)::geography AS location
FROM
crime_incidents ci
WHERE
ci.id = p_incident_id
AND (ci.locations->>'latitude') IS NOT NULL
AND (ci.locations->>'longitude') IS NOT NULL
),
unit_locations AS (
SELECT
u.code_unit,
u.name,
ST_SetSRID(ST_MakePoint(u.longitude, u.latitude), 4326)::geography AS location
FROM
units u
WHERE
u.latitude IS NOT NULL
AND u.longitude IS NOT NULL
)
SELECT
ul.code_unit as unit_code,
ul.name as unit_name,
ST_Distance(ul.location, il.location) as distance_meters
FROM
unit_locations ul
CROSS JOIN
incident_location il
WHERE
ST_DWithin(ul.location, il.location, p_max_distance_meters)
ORDER BY
ST_Distance(ul.location, il.location);
END;
$function$
;
-- create type "gis"."geometry_dump" as ("path" integer[], "geom" geometry);
-- create type "gis"."valid_detail" as ("valid" boolean, "reason" character varying, "location" geometry);