Não me lembro da última vez que precisei usar um cursor explícito para fazer um loop no plpgsql.
Use o cursor implícito de um
FOR
loop, isso é muito mais limpo: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
$$;
Você precisa incluir o nome do esquema para fazer isso funcionar para todos os esquemas (incluindo aqueles que não estão em seu
search_path
). Além disso, você precisa para usar
quote_ident()
ou format()
com %I
ou uma regclass
variável para proteção contra injeção de SQL. Um nome de tabela pode ser quase qualquer coisa entre aspas duplas. Ver:- Nome da tabela como parâmetro de função do PostgreSQL
Detalhe menor:escape do sublinhado (
_
) no LIKE
padrão para torná-lo um literal sublinhado:tablename NOT LIKE 'pg\_%'
Como posso fazer isso:
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
em vez de tablename
, ele fornece o OID da tabela. O tipo de identificador de objeto
regclass
é útil para simplificar. Em particular, os nomes das tabelas são colocados entre aspas duplas e qualificados pelo esquema quando necessário automaticamente (também evita a injeção de SQL). Esta consulta também exclui tabelas temporárias (o esquema temporário chama-se
pg_temp%
internamente). Para incluir apenas tabelas de um determinado esquema:
AND n.nspname = 'public' -- schema name here, case-sensitive