sql >> Base de Datos >  >> RDS >> PostgreSQL

Bucle en tablas con PL/pgSQL en Postgres 9.0+

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