Iteration on tables
I need to perform the same operation on multiple tables. Right now the request looks like this:
create view foobar
as
select this, that
from here
where this=1
union all
select this,that
from there
where this=1
..... .....
etc. for multiple tables. All results are combined.
Is there a way, instead of writing this very long query, where it's easy to get something wrong, write something like
for table in here, there, upthere
do
select this, that from $table where this=1
and then combine them all.
I have a query running right now and it will take a while, but this is just curiosity and I didn't know how to google it!
source to share
Create VIEW
from UNION
all required tables and then SELECT
from this VIEW
.
Alternatively, you can create VIEW
like this:
CREATE OR REPLACE VIEW table_set AS
SELECT 'table1' as table_name, field1, field2 ...
FROM table1
UNION ALL
SELECT 'table2' as table_name, field1, field2 ...
FROM table2
UNION ALL
SELECT 'table3' as table_name, field1, field2 ...
FROM table3
UNION ALL
...
and SELECT
from this VIEW
like:
SELECT field1, field3
FROM table_set
WHERE table_name IN ('table2','table4')
AND field5 = 'abc'
source to share
A view like @Igor desrcibes is one option.
If performance is significant and you don't have a lot of writes, you can use this view to (re) create a <strong> materialized view .
Or for shorter syntax and dynamic selection of source tables, you can use the plpgsql function like this one:
CREATE OR REPLACE FUNCTION f_select_from_tbls(tables text[], cond int)
RETURNS TABLE (this int, that text) AS
$BODY$
DECLARE
tbl text; -- automatically avoids SQLi
BEGIN
FOREACH tbl IN ARRAY tables LOOP
RETURN QUERY EXECUTE format('
SELECT this, that
FROM %I
WHERE this = $1', tbl)
USING cond;
END LOOP;
END
$BODY$
LANGUAGE plpgsql;
Call:
SELECT * FROM f_select_from_tbls('{t1,t2,nonStandard tablename}', 4);
I am assuming that multiple tables share columns with the same name and type (this int, that text)
(you are not defining data types in your question.) The function takes array of text
as table names and value integer
as a condition.
Read more about Looping Through Arrays in the manual.
Learn more about Returning from a function in the manual.
With dynamic SQL, you have to be wary of SQL injection . This threat is neutralized here in two ways:
- Table names in an array
tables
are entered by a functionformat()
that quotes any non-standard table name correctly - The parameter value is
cond
passed as throughUSING
, which makes SQLi impossible.
Option with VARIADIC
parameter
The goal is to make the function call easier. You can pass a list of text variables instead of building an array from them (the array is inline from parameters). It's all.
CREATE OR REPLACE FUNCTION f_select_from_tbls2(cond int, VARIADIC tables text[])
RETURNS TABLE (this int, that text) AS
$BODY$
DECLARE
tbl text; -- automatically avoids SQLi
BEGIN
FOREACH tbl IN ARRAY tables LOOP
RETURN QUERY EXECUTE format('
SELECT this, that
FROM %I
WHERE this = $1', tbl)
USING cond;
END LOOP;
END
$BODY$
LANGUAGE plpgsql;
I put it tables
last in this case to have an open end for the parameter VARIADIC
. Call:
SELECT * FROM f_select_from_tbls2(4, 't1','t2','iLLegal name')
source to share