What you are looking for is to actually do the INSERT into warehouse_maine
after Warehouse
DELIMITER $$
DROP TRIGGER IF EXISTS Warehouse_InsertAfter $$
CREATE TRIGGER Warehouse_InsertAfter AFTER INSERT ON Warehouse
FOR EACH ROW
BEGIN
IF NEW.state = 'maine' THEN
INSERT IGNORE INTO warehouse_maine (shipperid, name, state)
VALUES (NEW.shipperid, NEW.name, NEW.state);
END IF;
END;
DELIMITER ;
This trigger will do the job. If you are doing a bulk INSERT
of rows into the Warehouse
table, this trigger will slow things down a bit. If you plan to do such bulk INSERT
s, you are better off doing that in a single INSERT
:
INSERT IGNORE INTO warehouse_maine
SELECT * FROM Warehouse WHERE state='maine';
What you might need
You should be able to avoid all the complication with a simple SELECT
instead:
SELECT t.*, ST_Intersection(x.geom, t.geom) AS geom2
FROM tbl t -- replace tbl with actual table
JOIN ST_GeomFromText($clipper_geom, 4326) AS x(geom) ON ST_Intersects(x.geom, t.geom)
WHERE t.seq = $age_sequence;
Minor difference: you get the original geom
and the intersection geom2
in the result. Add the redundant ST_AsText(ST_Intersection(x.geom, t.geom)) AS clipped_geom_wkt
to the SELECT
list if you really need it.
What you ask
I understand your question like this:
I have various input tables, each has a column geom geometry
. I want a function to take a table name and clipper_geom geometry
as input and return all rows intersecting with my clipper_geom
. One column clipped_geom_wkt text
shall be appended and the value of geom
changed, each showing the intersection with clipper_geom
.
That's not trivial. SQL is a static language, a function demands to know the return type at call time at the latest. We can achieve dynamic results with polymorphic types, but we need a well-known row type to work with. The row type of an existing table is good for it, but you want to append another column. That's not easily possible. The workaround is to return the polymorphic row type, plus an extra column (like you seem to have tried already). Decompose the row type in the function call to arrive at your desired result:
CREATE OR REPLACE FUNCTION my_func(_tbl ANYELEMENT
, clipper_geom text
, age_sequence text)
RETURNS TABLE (tbl ANYELEMENT, clipped_geom_wkt text) AS
$func$
DECLARE
_geom geometry := ST_GeomFromText(clipper_geom, 4326); -- compute once
BEGIN
FOR tbl IN EXECUTE format(
'SELECT * FROM %s
WHERE seq = $1
AND ST_Intersects($2, geom)'
, pg_typeof(_tbl)
)
USING age_sequence -- data type must match!
, _geom
LOOP
tbl := tbl #= hstore('geom', ST_Intersection(_geom, tbl.geom));
clipped_geom_wkt := ST_AsText(tbl.geom);
RETURN NEXT;
END LOOP;
END
$func$ LANGUAGE plpgsql; -- don't quote the language name
Call (important!):
SELECT (tbl).*, clipped_geom_wkt
FROM my_func(NULL::public.clipped_table, $my_clipper_geom, $my_age_sequence);
Works for me in Postgres 10.
Notable features:
- Polymorphic types.
Note how the row variable tbl
is defined implicitly in the RETURNS
clause, where it copies the input type dynamically (ANYELEMENT
). So you are not bound to use SETOF
with polymorphic types like you speculated.
Related (you linked to that one yourself):
FOR-IN-EXECUTE
to loop over a dynamic query.
- Assignment of a yet-unknown column with the hstore operator
#=
. See:
- Decomposition of composite type in the function call with
(tbl).*
Simpler
I stuck to your design above, but it's unnecessary complication for the given example. The extra column clipped_geom_wkt
is completely redundant, just derive it from geom
in the function call. Then we can use the input type directly:
CREATE OR REPLACE FUNCTION my_func2(_tbl ANYELEMENT
, clipper_geom text
, age_sequence text)
RETURNS SETOF ANYELEMENT AS
$func$
DECLARE
_geom geometry := ST_GeomFromText(clipper_geom, 4326);
BEGIN
FOR _tbl IN EXECUTE format(
'SELECT * FROM %s
WHERE seq = $1
AND ST_Intersects($2, geom)'
, pg_typeof(_tbl)
)
USING age_sequence -- data type must match!
, _geom
LOOP
_tbl := _tbl #= hstore('geom', ST_Intersection(_geom, _tbl.geom));
RETURN NEXT _tbl;
END LOOP;
END
$func$ LANGUAGE plpgsql;
Call:
SELECT *, ST_AsText(geom) AS clipped_geom_wkt -- if you need the redundant column
FROM my_func2(NULL::public.clipped_table, $my_clipper_geom, $my_age_sequence);
Best Answer
It's documented with the SELECT statement and it's called "TABLE Command" there.
In the SQL standard it's called an "explicit table":
This seems to be part of the standard at least since SQL 1992