J'ai deux tables: l'événement et l'emplacementComment créer une fonction paginable dans PostgreSQL
CREATE TABLE location
(
location_id bigint NOT NULL,
version bigint NOT NULL,
active boolean NOT NULL,
created timestamp without time zone NOT NULL,
latitude double precision NOT NULL,
longitude double precision NOT NULL,
updated timestamp without time zone,
CONSTRAINT location_pkey PRIMARY KEY (location_id)
)
CREATE TABLE event
(
event_id bigint NOT NULL,
version bigint NOT NULL,
active boolean NOT NULL,
created timestamp without time zone NOT NULL,
end_date date,
entry_fee numeric(19,2),
location_id bigint NOT NULL,
organizer_id bigint NOT NULL,
start_date date NOT NULL,
timetable_id bigint,
updated timestamp without time zone,
CONSTRAINT event_pkey PRIMARY KEY (event_id),
CONSTRAINT fk_organizer FOREIGN KEY (organizer_id)
REFERENCES "user" (user_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT fk_timetable FOREIGN KEY (timetable_id)
REFERENCES timetable (timetable_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT fk_location FOREIGN KEY (location_id)
REFERENCES location (location_id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
D'autres tableaux sont de moindre importance à aucune sorte qu'ils ne seront pas affichées (sauf demande explicite).
Et pour ces tables, en utilisant cube
et earthdistance
extensions pgsql J'ai créé la fonction suivante pour trouver tous les event_ids dans un certain rayon d'un certain point.
CREATE OR REPLACE FUNCTION eventidswithinradius(
lat double precision,
lng double precision,
radius double precision)
RETURNS SETOF bigint AS
$BODY$
BEGIN
RETURN QUERY SELECT event.event_id
FROM event
INNER JOIN location ON location.location_id = event.location_id
WHERE earth_box(ll_to_earth(lat, lng), radius) @> ll_to_earth(location.latitude, location.longitude);
END;
$BODY$
Et cela fonctionne comme prévu. Maintenant, je souhaite le rendre paginable, et je suis coincé sur la façon d'obtenir toutes les valeurs nécessaires (la table avec le contenu paginé et le nombre total).
Jusqu'à présent, j'ai créé ceci:
CREATE OR REPLACE FUNCTION pagedeventidswithinradius(
IN lat double precision,
IN lng double precision,
IN radius double precision,
IN page_size integer,
IN page_offset integer)
RETURNS TABLE(total_size integer , event_id bigint) AS
$BODY$
DECLARE total integer;
BEGIN
SELECT COUNT(location.*) INTO total FROM location WHERE earth_box(ll_to_earth(lat, lng), radius) @> ll_to_earth(location.latitude, location.longitude);
RETURN QUERY SELECT total, event.event_id as event_id
FROM event
INNER JOIN location ON location.location_id = event.location_id
WHERE earth_box(ll_to_earth(lat, lng), radius) @> ll_to_earth(location.latitude, location.longitude)
ORDER BY event_id
LIMIT page_size OFFSET page_offset;
END;
$BODY$
Ici le nombre est appelé une seule fois et stocké dans une variable puisque je suppose que si je plaçais COUNT
dans la requête de retour lui-même, il serait appelé pour chaque ligne . Ce type de travaux, mais il est difficile d'analyser sur le back-end puisque le résultat est sous la forme de (count, event_id)
, également le nombre est inutilement répété sur toutes les lignes de résultat. J'espérais pouvoir simplement ajouter total
comme un paramètre OUT
et avoir la fonction retourner la table et remplir la variable OUT avec le nombre total, mais il semble que ce n'est pas autorisé. Je peux toujours faire en sorte que le décompte soit une fonction distincte, mais je me demandais s'il y avait une meilleure façon d'aborder cette question?
Pourquoi voulez-vous à la page cela? Puisque vous ne renvoyez qu'un seul 'bigint' par ligne, la consommation de ressources ne poserait pas de problème ici. – Patrick
Oui, cependant, ces bigints représentent des identifiants qui seront utilisés pour extraire des données complètes en utilisant ORM. L'ORM ne peut pas appeler fonctions/sp, il s'agit donc d'une solution de contournement pour récupérer les ID paginés, puis utiliser ORM pour obtenir ces éléments correctement mappés. – MrPlow