Skip to content

Instantly share code, notes, and snippets.

@temoto
Created April 6, 2012 13:50
Show Gist options
  • Save temoto/2319942 to your computer and use it in GitHub Desktop.
Save temoto/2319942 to your computer and use it in GitHub Desktop.
plpgsql for loop -> single select?
-- Types: ticket_query, ticket_result
-- Functions: ticket_search_1, ticket_unique_sellers
drop type ticket_query cascade;
create type ticket_query as (
cities_from text[],
cities_to text[],
date_direct date,
date_back_min date,
date_back_max date,
expires timestamp(0) without time zone,
modified timestamp(0) without time zone,
adults smallint,
children smallint,
infants smallint,
sellers_1_adult smallint[],
limit_filter smallint
);
create type ticket_result as (
id uuid,
adults smallint,
children smallint,
infants smallint,
seller smallint,
city_from char(3),
city_to char(3),
date_direct date,
date_back date,
cost integer,
expires timestamp(0) without time zone,
url text,
modified timestamp(0) without time zone,
seller_data bytea,
data bytea
);
create or replace function ticket_search_1(q ticket_query) returns setof ticket_result as $$
declare
s text;
suffix text;
begin
suffix := replace(q.date_direct::text, '-', '_');
-- for s in
-- execute 'explain analyze select distinct on (id) q1.*
return query execute 'select distinct on (id) q1.*
from (
select ticket.id, $7, $8, $9, seller,
ticket.city_from, ticket.city_to, ticket.date_direct, ticket.date_back, cost,
ticket.expires, url, modified, seller_data, route.data
from ticket_' || suffix || ' as ticket, route_' || suffix || ' as route
where ticket.id = route.id
and ' || (case when array_length(q.cities_from, 1) = 1 then 'ticket.city_from = $1[1]'
else 'ticket.city_from = any($1)'
end) || '
and ' || (case when array_length(q.cities_to, 1) = 1 then 'ticket.city_to = $2[1]'
else 'ticket.city_to = any($2)'
end) || '
and ' || (case when q.date_back_min is null then 'ticket.date_back is null'
else 'ticket.date_back between $3 and $4'
end) || '
and ($5 is null or ticket.expires >= $5)
and ($6 is null or ticket.modified > $6)
and (case when seller = any($10) then (adults = 1 and children = 0 and infants = 0)
else (adults = $7 and children = $8 and infants = $9)
end)
order by cost
limit $11
) as q1
order by id, cost' using q.cities_from, q.cities_to, q.date_back_min, q.date_back_max, q.expires,
q.modified, q.adults, q.children, q.infants, q.sellers_1_adult, q.limit_filter, suffix
;
-- loop
-- raise notice '%', s;
-- end loop;
end;
$$ language 'plpgsql';
create or replace function ticket_search_2(direct_dates date[], base_query ticket_query) returns setof ticket_result as $$
declare
d date;
q ticket_query;
begin
for d in (select * from unnest(direct_dates)) loop
q = base_query;
q.date_direct = d;
return query select * from ticket_search_1(q);
end loop;
end;
$$ language 'plpgsql';
create or replace function search_2(direct_dates date[], base_query query) returns setof result as $$
declare
d date;
q query;
begin
for d in (select * from unnest(direct_dates)) loop
q = base_query;
q.date_direct = d;
return query select * from search_1(q);
end loop;
end;
$$ language 'plpgsql';
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment