Needed to drop every table in a schema whose name starts with stale_. My instinct was to pipe psql output to a shell script that pipes back into psql. Gross.

Turns out psql has \gexec, which executes the text output of the previous query as SQL.

SELECT 'DROP TABLE ' || quote_ident(schemaname) || '.' || quote_ident(tablename) || ' CASCADE;'
FROM pg_tables
WHERE tablename LIKE 'stale_%';
\gexec

The SELECT produces a column of DROP TABLE statements. \gexec runs them. No shell loop, no sed, no injection risk if you remember quote_ident.

Also works great for generating ALTER TABLE statements in bulk:

SELECT 'ALTER TABLE ' || quote_ident(table_name)
       || ' SET (autovacuum_vacuum_scale_factor = 0.05);'
FROM information_schema.tables
WHERE table_schema = 'public' AND table_name LIKE 'events_%';
\gexec

The only gotcha: output is run statement-by-statement, so if one fails the next ones still run (unless you’re in a transaction block). I now wrap it in BEGIN/COMMIT when I want all-or-nothing.

Wish I’d known this about five years ago.