No puedo recordar la última vez que realmente necesité usar un cursor explícito para hacer un bucle en plpgsql.
Use el cursor implícito de un FOR
bucle, eso es mucho más limpio:
DO
$$
DECLARE
rec record;
nbrow bigint;
BEGIN
FOR rec IN
SELECT *
FROM pg_tables
WHERE tablename NOT LIKE 'pg\_%'
ORDER BY tablename
LOOP
EXECUTE 'SELECT count(*) FROM '
|| quote_ident(rec.schemaname) || '.'
|| quote_ident(rec.tablename)
INTO nbrow;
-- Do something with nbrow
END LOOP;
END
$$;
Debe incluir el nombre del esquema para que funcione para todos los esquemas (incluidos los que no están en su search_path
). ).
Además, en realidad necesitas usar quote_ident()
o format()
con %I
o una regclass
variable para salvaguardar contra la inyección SQL. El nombre de una tabla puede ser casi cualquier cosa dentro de comillas dobles. Ver:
- Nombre de tabla como parámetro de función de PostgreSQL
Detalle menor:escapar del guión bajo (_
) en el LIKE
patrón para que sea un literal guión bajo:tablename NOT LIKE 'pg\_%'
Cómo podría hacerlo:
DO
$$
DECLARE
tbl regclass;
nbrow bigint;
BEGIN
FOR tbl IN
SELECT c.oid
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
AND n.nspname NOT LIKE 'pg\_%' -- system schema(s)
AND n.nspname <> 'information_schema' -- information schema
ORDER BY n.nspname, c.relname
LOOP
EXECUTE 'SELECT count(*) FROM ' || tbl INTO nbrow;
-- raise notice '%: % rows', tbl, nbrow;
END LOOP;
END
$$;
Consulta pg_catalog.pg_class
en lugar de tablename
, proporciona el OID de la tabla.
El tipo de identificador de objeto regclass
es útil para simplificar. En particular, los nombres de las tablas aparecen entre comillas dobles y se califican según el esquema automáticamente cuando es necesario (también evita la inyección de SQL).
Esta consulta también excluye las tablas temporales (el esquema temporal se llama pg_temp%
internamente).
Para incluir solo tablas de un esquema dado:
AND n.nspname = 'public' -- schema name here, case-sensitive